├── .gitignore ├── bin └── sofixer64 ├── src ├── lib.rs ├── utils │ ├── mod.rs │ ├── types.rs │ └── process.rs ├── dumper │ ├── mod.rs │ ├── sofixer.rs │ ├── dexdumper.rs │ └── sodumper.rs └── main.rs ├── README.md ├── Cargo.toml └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .cargo -------------------------------------------------------------------------------- /bin/sofixer64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mrack/TinyDump/HEAD/bin/sofixer64 -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod dumper; 2 | pub mod utils; 3 | 4 | pub use dumper::{DexDumper, SoDumper}; 5 | pub use utils::*; 6 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod process; 2 | pub mod types; 3 | 4 | pub use process::*; 5 | pub use types::*; 6 | pub use process::SoFileInfo; 7 | -------------------------------------------------------------------------------- /src/dumper/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod dexdumper; 2 | pub mod sodumper; 3 | pub mod sofixer; 4 | 5 | pub use dexdumper::DexDumper; 6 | pub use sodumper::SoDumper; 7 | -------------------------------------------------------------------------------- /src/utils/types.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct MemoryMapping { 3 | pub start: u64, 4 | pub end: u64, 5 | #[allow(dead_code)] 6 | pub permissions: String, 7 | #[allow(dead_code)] 8 | pub offset: u64, 9 | #[allow(dead_code)] 10 | pub device: String, 11 | #[allow(dead_code)] 12 | pub inode: u64, 13 | pub pathname: String, 14 | } 15 | 16 | #[derive(Debug)] 17 | pub struct SoInfo { 18 | pub base: u64, 19 | pub size: u64, 20 | pub next: u64, 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyDump 2 | 3 | Android native SO and DEX dumper. 4 | 5 | ## Features 6 | 7 | - **SO Dump**: Extract SO files from running Android processes 8 | - **DEX Dump**: Extract DEX files from running Android processes 9 | - **SO List**: List all SO files loaded by a process 10 | - **Auto-Fix**: Integrated SoFixer for automatic SO file repair 11 | 12 | ## Build 13 | 14 | ```bash 15 | # ARM64 Android 16 | cargo build --target aarch64-linux-android --release 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```bash 22 | # List all SO files 23 | ./tinydump --list-so -p 24 | ./tinydump --list-so -n 25 | 26 | # Dump SO file 27 | ./tinydump -t -p -o 28 | 29 | # Dump DEX files 30 | ./tinydump --dex -p -o 31 | ``` 32 | 33 | ## Requirements 34 | 35 | - **Root access only** 36 | - Android device with root access 37 | - ARM64 architecture 38 | 39 | ## License 40 | 41 | MIT License 42 | 43 | ## Thanks 44 | https://github.com/F8LEFT/SoFixer 45 | https://github.com/SeeFlowerX/frida_dump 46 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tinydump" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["mrack "] 6 | description = "Android native SO and DEX dumper" 7 | license = "MIT" 8 | repository = "https://github.com/mrack/tinydump" 9 | keywords = ["android", "dumper", "reverse-engineering", "memory", "sofixer"] 10 | categories = ["system", "command-line-utilities"] 11 | 12 | [dependencies] 13 | anyhow = "1.0" 14 | clap = { version = "4.0", features = ["derive"] } 15 | byteorder = "1.4" 16 | goblin = "0.8" 17 | nix = "0.26" 18 | proc-maps = "0.2" 19 | regex = "1.0" 20 | thiserror = "1.0" 21 | log = "0.4" 22 | env_logger = "0.10" 23 | indicatif = "0.17" 24 | 25 | # Android-specific dependencies 26 | [target.'cfg(target_os = "android")'.dependencies] 27 | android_logger = "0.13" 28 | 29 | [profile.release] 30 | opt-level = 3 31 | lto = true 32 | codegen-units = 1 33 | panic = "abort" 34 | 35 | [profile.dev] 36 | opt-level = 0 37 | debug = true 38 | 39 | 40 | # Android build configurations 41 | [target.aarch64-linux-android] 42 | rustflags = [ 43 | "-C", "link-arg=-Wl,--as-needed", 44 | "-C", "link-arg=-Wl,--strip-all", 45 | ] 46 | -------------------------------------------------------------------------------- /src/dumper/sofixer.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use std::fs; 3 | use std::io::Write; 4 | use std::path::Path; 5 | use std::process::Command; 6 | 7 | // SoFixer64 binary data will be embedded here 8 | // Author: mrack 9 | const SOFIXER64_BINARY: &[u8] = include_bytes!("../../bin/sofixer64"); 10 | 11 | pub struct SoFixer { 12 | binary_path: String, 13 | } 14 | 15 | impl SoFixer { 16 | pub fn new() -> Result { 17 | let binary_path = "./SoFixer".to_string(); 18 | Ok(Self { binary_path }) 19 | } 20 | 21 | pub fn extract(&self) -> Result<()> { 22 | let output_path = Path::new(&self.binary_path); 23 | 24 | if let Some(parent) = output_path.parent() { 25 | fs::create_dir_all(parent)?; 26 | } 27 | 28 | let mut file = fs::File::create(output_path)?; 29 | file.write_all(SOFIXER64_BINARY)?; 30 | 31 | #[cfg(unix)] 32 | { 33 | use std::os::unix::fs::PermissionsExt; 34 | let mut perms = fs::metadata(output_path)?.permissions(); 35 | perms.set_mode(0o755); 36 | fs::set_permissions(output_path, perms)?; 37 | } 38 | 39 | println!("[+] SoFixer extracted to: {}", self.binary_path); 40 | Ok(()) 41 | } 42 | 43 | pub fn fix_so(&self, base: u64, so_path: &str, output_path: &str) -> Result<()> { 44 | if !Path::new(&self.binary_path).exists() { 45 | self.extract()?; 46 | } 47 | 48 | let output = Command::new(&self.binary_path) 49 | .arg("-m") 50 | .arg(format!("{:#x}", base)) 51 | .arg("-s") 52 | .arg(so_path) 53 | .arg("-o") 54 | .arg(output_path) 55 | .output()?; 56 | 57 | if !output.status.success() { 58 | let stderr = String::from_utf8_lossy(&output.stderr); 59 | return Err(anyhow!("SoFixer failed: {}", stderr)); 60 | } 61 | 62 | let stdout = String::from_utf8_lossy(&output.stdout); 63 | if !stdout.is_empty() { 64 | println!("[+] SoFixer output: {}", stdout); 65 | } 66 | 67 | println!("[+] SO fixed successfully: {}", output_path); 68 | Ok(()) 69 | } 70 | 71 | pub fn cleanup(&self) -> Result<()> { 72 | if Path::new(&self.binary_path).exists() { 73 | fs::remove_file(&self.binary_path)?; 74 | println!("[+] SoFixer binary cleaned up"); 75 | } 76 | Ok(()) 77 | } 78 | } 79 | 80 | impl Drop for SoFixer { 81 | fn drop(&mut self) { 82 | let _ = self.cleanup(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod dumper; 2 | mod utils; 3 | 4 | use anyhow::{anyhow, Result}; 5 | use clap::Parser; 6 | use std::path::PathBuf; 7 | 8 | use dumper::{DexDumper, SoDumper}; 9 | use utils::{get_pid_by_name, list_so_files}; 10 | 11 | #[derive(Parser, Debug)] 12 | #[command(name = "tinydump")] 13 | #[command(about = "Android native SO and DEX dumper")] 14 | #[command(version)] 15 | #[command(author = "mrack ")] 16 | struct Args { 17 | #[arg(short, long)] 18 | target: Option, 19 | 20 | #[arg(short = 'p', long)] 21 | attach_pid: Option, 22 | 23 | #[arg(short = 'n', long)] 24 | attach_name: Option, 25 | 26 | #[arg(short, long, default_value = ".")] 27 | output: PathBuf, 28 | 29 | #[arg(long)] 30 | dex: bool, 31 | 32 | #[arg(long)] 33 | list_so: bool, 34 | } 35 | 36 | fn main() -> Result<()> { 37 | let args = Args::parse(); 38 | 39 | let target_pid = if let Some(pid) = args.attach_pid { 40 | pid 41 | } else { 42 | let process_name = args 43 | .attach_name 44 | .ok_or_else(|| anyhow!("Need --attach-pid or --attach-name"))?; 45 | get_pid_by_name(&process_name)? 46 | }; 47 | 48 | std::fs::create_dir_all(&args.output)?; 49 | 50 | if args.list_so { 51 | // 列举SO文件模式 52 | println!("[+] SO list mode"); 53 | println!("[+] PID: {}", target_pid); 54 | 55 | let so_files = list_so_files(target_pid) 56 | .map_err(|e| anyhow!("Failed to list SO files: {}", e))?; 57 | 58 | if so_files.is_empty() { 59 | println!("[!] No SO files found for PID {}", target_pid); 60 | } else { 61 | println!("[+] Found {} SO files:", so_files.len()); 62 | println!("{:<50} {:<18} {:<18} {:<10} {:<20}", "Name", "Start", "End", "Size", "Permissions"); 63 | println!("{:-<120}", ""); 64 | 65 | for so in so_files { 66 | let size_str = format!("{}KB", so.size / 1024); 67 | 68 | println!("{:<50} {:<18x} {:<18x} {:<10} {:<20}", 69 | so.name, so.start, so.end, size_str, so.permissions); 70 | } 71 | } 72 | } else if args.dex { 73 | // DEX模式 74 | println!("[+] DEX dump mode"); 75 | println!("[+] PID: {}", target_pid); 76 | println!("[+] Output: {}", args.output.display()); 77 | 78 | let mut dex_dumper = 79 | DexDumper::new(target_pid as i32).map_err(|e| anyhow!("DexDumper failed: {}", e))?; 80 | 81 | dex_dumper 82 | .attach_process() 83 | .map_err(|e| anyhow!("Attach failed: {}", e))?; 84 | 85 | dex_dumper 86 | .search_dex(&args.output.to_string_lossy()) 87 | .map_err(|e| anyhow!("DEX search failed: {}", e))?; 88 | 89 | println!("[+] DEX dump done"); 90 | } else { 91 | // SO dump模式 92 | let target_name = args 93 | .target 94 | .ok_or_else(|| anyhow!("Need --target for SO dump"))?; 95 | 96 | let dumper = SoDumper::new(target_pid, target_name, args.output) 97 | .map_err(|e| anyhow!("SoDumper failed: {}", e))?; 98 | dumper.dump()?; 99 | 100 | println!("[+] SO dump done"); 101 | } 102 | 103 | Ok(()) 104 | } 105 | -------------------------------------------------------------------------------- /src/utils/process.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use std::collections::HashMap; 3 | 4 | pub fn get_pid_by_name(process_name: &str) -> Result { 5 | let proc_dir = std::fs::read_dir("/proc")?; 6 | 7 | for entry in proc_dir { 8 | let entry = entry?; 9 | let file_name = entry.file_name(); 10 | let pid_str = file_name.to_string_lossy(); 11 | 12 | if let Ok(pid) = pid_str.parse::() { 13 | let cmdline_path = format!("/proc/{}/cmdline", pid); 14 | if let Ok(cmdline) = std::fs::read_to_string(&cmdline_path) { 15 | if cmdline.contains(process_name) { 16 | return Ok(pid); 17 | } 18 | } 19 | } 20 | } 21 | 22 | Err(anyhow!("Process {} not found", process_name)) 23 | } 24 | 25 | /// 列举指定PID的所有SO文件 26 | pub fn list_so_files(pid: u32) -> Result> { 27 | let maps_path = format!("/proc/{}/maps", pid); 28 | let content = std::fs::read_to_string(&maps_path) 29 | .map_err(|_| anyhow!("Failed to read /proc/{}/maps", pid))?; 30 | 31 | let mut so_files: HashMap = HashMap::new(); 32 | 33 | for line in content.lines() { 34 | if line.contains(".so") { 35 | let parts: Vec<&str> = line.split_whitespace().collect(); 36 | if parts.len() >= 6 { 37 | let addr_range: Vec<&str> = parts[0].split('-').collect(); 38 | if addr_range.len() == 2 { 39 | if let (Ok(start), Ok(end)) = ( 40 | u64::from_str_radix(addr_range[0], 16), 41 | u64::from_str_radix(addr_range[1], 16), 42 | ) { 43 | let permissions = parts[1].to_string(); 44 | let pathname = parts[5..].join(" "); 45 | 46 | if !pathname.is_empty() && pathname.contains(".so") { 47 | let so_name = pathname.split('/').last().unwrap_or(&pathname).to_string(); 48 | 49 | if let Some(existing) = so_files.get_mut(&so_name) { 50 | // 如果已存在同名SO,更新地址范围 51 | existing.start = existing.start.min(start); 52 | existing.end = existing.end.max(end); 53 | existing.size = existing.end - existing.start; 54 | } else { 55 | so_files.insert(so_name.clone(), SoFileInfo { 56 | name: so_name, 57 | path: pathname, 58 | start, 59 | end, 60 | size: end - start, 61 | permissions, 62 | }); 63 | } 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | let mut result: Vec = so_files.into_values().collect(); 72 | result.sort_by(|a, b| a.start.cmp(&b.start)); 73 | Ok(result) 74 | } 75 | 76 | /// SO文件信息结构体 77 | #[derive(Debug, Clone)] 78 | pub struct SoFileInfo { 79 | pub name: String, 80 | pub path: String, 81 | pub start: u64, 82 | pub end: u64, 83 | pub size: u64, 84 | pub permissions: String, 85 | } 86 | -------------------------------------------------------------------------------- /src/dumper/dexdumper.rs: -------------------------------------------------------------------------------- 1 | use nix::sys::signal::{kill, Signal}; 2 | use nix::unistd::Pid; 3 | use proc_maps::MapRange; 4 | 5 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 6 | use regex::bytes::Regex; 7 | use std::cell::RefCell; 8 | use std::io::{Cursor, Read, Seek, SeekFrom, Write}; 9 | use std::path::Path; 10 | 11 | // Constants for DEX file structure 12 | // Author: mrack 13 | const DEX_MAGIC: &[u8] = b"dex\n035\0"; 14 | const DEX_HEADER_SIZE: u32 = 0x70; 15 | const DEX_HEADER_SIZE_OFFSET: u64 = 0x24; 16 | const DEX_FILE_SIZE_OFFSET: u64 = 0x20; 17 | const DEX_ENDIAN_TAG_OFFSET: u64 = 0x28; 18 | const DEX_STRING_IDS_OFFSET: u64 = 0x3c; 19 | const DEX_MAP_OFFSET: u64 = 0x34; 20 | const DEX_ENDIAN_TAG: u32 = 0x12345678; 21 | const DEX_ENDIAN_TAG_SWAPPED: u32 = 0x78563412; 22 | const MIN_MEMORY_SIZE: usize = 0x60; 23 | 24 | #[derive(Debug)] 25 | pub enum DexDumperError { 26 | ProcessNotFound(i32), 27 | FailedToAttach, 28 | FailedToDetach, 29 | FileCreationFailed, 30 | IoError(std::io::Error), 31 | } 32 | 33 | impl std::fmt::Display for DexDumperError { 34 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 35 | match self { 36 | DexDumperError::ProcessNotFound(pid) => write!(f, "Process {} not found", pid), 37 | DexDumperError::FailedToAttach => write!(f, "Failed to attach to process"), 38 | DexDumperError::FailedToDetach => write!(f, "Failed to detach from process"), 39 | DexDumperError::FileCreationFailed => write!(f, "Failed to create output file"), 40 | DexDumperError::IoError(e) => write!(f, "IO error: {}", e), 41 | } 42 | } 43 | } 44 | 45 | impl std::error::Error for DexDumperError {} 46 | 47 | impl From for DexDumperError { 48 | fn from(err: std::io::Error) -> Self { 49 | DexDumperError::IoError(err) 50 | } 51 | } 52 | 53 | pub struct DexDumper { 54 | pid: Pid, 55 | mem_fd: RefCell, 56 | maps: Vec, 57 | dex_regex: Regex, 58 | } 59 | 60 | impl DexDumper { 61 | pub fn new(pid: i32) -> Result { 62 | let mem_fd = std::fs::File::open(format!("/proc/{}/mem", pid)) 63 | .map_err(|_| DexDumperError::ProcessNotFound(pid))?; 64 | 65 | let dex_regex = 66 | Regex::new(r"\x64\x65\x78\x0a\x30..\x00").expect("Failed to compile DEX regex"); 67 | 68 | Ok(DexDumper { 69 | pid: Pid::from_raw(pid), 70 | maps: Vec::new(), 71 | mem_fd: RefCell::new(mem_fd), 72 | dex_regex, 73 | }) 74 | } 75 | 76 | pub fn attach_process(&mut self) -> Result<(), DexDumperError> { 77 | kill(self.pid, Signal::SIGSTOP).map_err(|_| DexDumperError::FailedToAttach)?; 78 | 79 | self.maps = proc_maps::get_process_maps(self.pid.as_raw()) 80 | .map_err(|_| DexDumperError::FailedToAttach)?; 81 | 82 | Ok(()) 83 | } 84 | 85 | pub fn detach_process(&self) -> Result<(), DexDumperError> { 86 | kill(self.pid, Signal::SIGCONT).map_err(|_| DexDumperError::FailedToDetach) 87 | } 88 | 89 | fn read_dex_header_value(&self, address: usize, offset: u64) -> Option { 90 | let mut cursor = self.mem_fd.borrow_mut(); 91 | cursor.seek(SeekFrom::Start(address as u64 + offset)).ok()?; 92 | cursor.read_u32::().ok() 93 | } 94 | 95 | fn guess_dex_size(&self, dex_header_addr: usize) -> Option<(usize, usize)> { 96 | let file_size = self.read_dex_header_value(dex_header_addr, DEX_FILE_SIZE_OFFSET)?; 97 | 98 | let string_ids_off = self.read_dex_header_value(dex_header_addr, DEX_STRING_IDS_OFFSET)?; 99 | if string_ids_off != DEX_HEADER_SIZE { 100 | return None; 101 | } 102 | 103 | let map_off = self.read_dex_header_value(dex_header_addr, DEX_MAP_OFFSET)?; 104 | let map_size = self.read_dex_header_value(dex_header_addr + map_off as usize, 0)?; 105 | 106 | let real_size = map_off 107 | .checked_add(map_size.checked_mul(0xC)?)? 108 | .checked_add(4)?; 109 | 110 | Some((file_size as usize, real_size as usize)) 111 | } 112 | 113 | fn fix_dex_header(dex: &[u8]) -> Option> { 114 | let mut fixed_dex = dex.to_vec(); 115 | let mut cursor = Cursor::new(&mut fixed_dex); 116 | 117 | cursor.write_all(DEX_MAGIC).ok()?; 118 | 119 | cursor.seek(SeekFrom::Start(DEX_FILE_SIZE_OFFSET)).ok()?; 120 | cursor.write_u32::(dex.len() as u32).ok()?; 121 | 122 | cursor.seek(SeekFrom::Start(DEX_HEADER_SIZE_OFFSET)).ok()?; 123 | cursor.write_u32::(DEX_HEADER_SIZE).ok()?; 124 | 125 | cursor.seek(SeekFrom::Start(DEX_ENDIAN_TAG_OFFSET)).ok()?; 126 | let endian_tag = cursor.read_u32::().ok()?; 127 | if endian_tag != DEX_ENDIAN_TAG && endian_tag != DEX_ENDIAN_TAG_SWAPPED { 128 | cursor.seek(SeekFrom::Start(DEX_ENDIAN_TAG_OFFSET)).ok()?; 129 | cursor.write_u32::(DEX_ENDIAN_TAG).ok()?; 130 | } 131 | 132 | Some(fixed_dex) 133 | } 134 | 135 | fn should_skip_memory_region(filename: Option<&std::path::Path>) -> bool { 136 | if let Some(f) = filename { 137 | f.starts_with("/data/dalvik-cache/") || f.starts_with("/system/") 138 | } else { 139 | false 140 | } 141 | } 142 | 143 | fn process_dex_found(&self, out_path: &Path, real_addr: usize) -> Result<(), DexDumperError> { 144 | if let Some((file_size, actual_size)) = self.guess_dex_size(real_addr) { 145 | if let Some(data) = self.read_memory_proc(real_addr, actual_size) { 146 | println!( 147 | "Found DEX at {:#08x}, file_size: {:#08x}, actual_size: {:#08x}", 148 | real_addr, file_size, actual_size 149 | ); 150 | 151 | let output_path = out_path.join(format!("dex_{:#08x}.dex", real_addr)); 152 | let mut file = std::fs::File::create(&output_path) 153 | .map_err(|_| DexDumperError::FileCreationFailed)?; 154 | 155 | file.write_all(&data)?; 156 | println!("Saved DEX to: {}", output_path.display()); 157 | } else { 158 | println!( 159 | "Failed to read memory at {:#08x} - {:#08x}", 160 | real_addr, 161 | real_addr + actual_size 162 | ); 163 | } 164 | } 165 | Ok(()) 166 | } 167 | 168 | fn process_memory_region( 169 | &self, 170 | out_path: &Path, 171 | memory_map: &MapRange, 172 | ) -> Result<(), DexDumperError> { 173 | if let Some(mem) = self.read_memory_proc(memory_map.start(), memory_map.size()) { 174 | for dex_match in self.dex_regex.find_iter(&mem) { 175 | let real_addr = memory_map.start() + dex_match.start(); 176 | self.process_dex_found(out_path, real_addr)?; 177 | } 178 | 179 | if mem.len() >= 3 && &mem[0..3] != b"dex" { 180 | if let Some((file_size, guess_size)) = self.guess_dex_size(memory_map.start()) { 181 | println!( 182 | "No header found, file_size: {:#08x}, guess_size: {:#08x}", 183 | file_size, guess_size 184 | ); 185 | 186 | if let Some(data) = self.read_memory_proc(memory_map.start(), guess_size) { 187 | if let Some(fixed_dex) = Self::fix_dex_header(&data) { 188 | let output_path = 189 | out_path.join(format!("dex_{:#08x}.dex", memory_map.start())); 190 | let mut file = std::fs::File::create(&output_path) 191 | .map_err(|_| DexDumperError::FileCreationFailed)?; 192 | 193 | file.write_all(&fixed_dex)?; 194 | println!("Saved fixed DEX to: {}", output_path.display()); 195 | } 196 | } else { 197 | println!( 198 | "Failed to read memory at {:#08x} - {:#08x}", 199 | memory_map.start(), 200 | memory_map.start() + guess_size 201 | ); 202 | } 203 | } 204 | } 205 | } 206 | Ok(()) 207 | } 208 | 209 | pub fn search_dex(&mut self, out_path: &str) -> Result<(), DexDumperError> { 210 | let out_path = Path::new(out_path); 211 | 212 | std::fs::create_dir_all(out_path)?; 213 | 214 | let filtered_maps: Vec<_> = self 215 | .maps 216 | .iter() 217 | .filter(|m| m.is_read() && m.size() > MIN_MEMORY_SIZE) 218 | .filter(|m| !Self::should_skip_memory_region(m.filename())) 219 | .collect(); 220 | 221 | println!( 222 | "Searching {} memory regions for DEX files...", 223 | filtered_maps.len() 224 | ); 225 | 226 | for memory_map in filtered_maps { 227 | if let Err(e) = self.process_memory_region(out_path, memory_map) { 228 | eprintln!( 229 | "Error processing memory region {:#08x}: {}", 230 | memory_map.start(), 231 | e 232 | ); 233 | } 234 | } 235 | 236 | println!("DEX search completed"); 237 | Ok(()) 238 | } 239 | 240 | fn read_memory_proc(&self, address: usize, size: usize) -> Option> { 241 | let mut buffer = vec![0u8; size]; 242 | let mut mem_fd = self.mem_fd.borrow_mut(); 243 | 244 | if mem_fd.seek(SeekFrom::Start(address as u64)).is_err() { 245 | return None; 246 | } 247 | 248 | if mem_fd.read_exact(&mut buffer).is_err() { 249 | return None; 250 | } 251 | 252 | Some(buffer) 253 | } 254 | } 255 | 256 | impl Drop for DexDumper { 257 | fn drop(&mut self) { 258 | let _ = self.detach_process(); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/dumper/sodumper.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use byteorder::{LittleEndian, ReadBytesExt}; 3 | use goblin::elf::Elf; 4 | use nix::sys::signal::{kill, Signal}; 5 | use nix::unistd::Pid; 6 | use std::fs::File; 7 | use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, Write}; 8 | use std::path::{Path, PathBuf}; 9 | 10 | use super::sofixer::SoFixer; 11 | use crate::utils::{MemoryMapping, SoInfo}; 12 | 13 | // Author: mrack 14 | pub struct SoDumper { 15 | target_pid: u32, 16 | target_name: String, 17 | output_dir: PathBuf, 18 | sofixer: SoFixer, 19 | auto_fix: bool, 20 | } 21 | 22 | impl SoDumper { 23 | pub fn new(target_pid: u32, target_name: String, output_dir: PathBuf) -> Result { 24 | let sofixer = SoFixer::new()?; 25 | Ok(Self { 26 | target_pid, 27 | target_name, 28 | output_dir, 29 | sofixer, 30 | auto_fix: true, 31 | }) 32 | } 33 | 34 | pub fn extract_sofixer(&self) -> Result<()> { 35 | self.sofixer.extract() 36 | } 37 | 38 | fn get_solist_offset(&self) -> Result { 39 | let linker_path = "/system/bin/linker64"; 40 | let mut file = File::open(linker_path)?; 41 | let mut buffer = Vec::new(); 42 | file.read_to_end(&mut buffer)?; 43 | 44 | let elf = Elf::parse(&buffer)?; 45 | 46 | for sym in elf.syms.iter() { 47 | if let Some(name) = elf.strtab.get_at(sym.st_name) { 48 | if name.contains("__dl__ZL6solist") { 49 | return Ok(sym.st_value); 50 | } 51 | } 52 | } 53 | 54 | Err(anyhow!("Could not find solist symbol in linker64")) 55 | } 56 | 57 | fn stop_process(&self) -> Result<()> { 58 | kill(Pid::from_raw(self.target_pid as i32), Signal::SIGSTOP)?; 59 | println!("[+] Process {} stopped", self.target_pid); 60 | Ok(()) 61 | } 62 | 63 | fn continue_process(&self) -> Result<()> { 64 | kill(Pid::from_raw(self.target_pid as i32), Signal::SIGCONT)?; 65 | println!("[+] Process {} continued", self.target_pid); 66 | Ok(()) 67 | } 68 | 69 | fn parse_proc_maps(&self) -> Result> { 70 | let maps_path = format!("/proc/{}/maps", self.target_pid); 71 | let file = File::open(&maps_path)?; 72 | let reader = BufReader::new(file); 73 | let mut mappings = Vec::new(); 74 | 75 | for line in reader.lines() { 76 | let line = line?; 77 | let parts: Vec<&str> = line.split_whitespace().collect(); 78 | 79 | if parts.len() >= 6 { 80 | let addr_range: Vec<&str> = parts[0].split('-').collect(); 81 | let start = u64::from_str_radix(addr_range[0], 16)?; 82 | let end = u64::from_str_radix(addr_range[1], 16)?; 83 | let permissions = parts[1].to_string(); 84 | let offset = u64::from_str_radix(parts[2], 16)?; 85 | let device = parts[3].to_string(); 86 | let inode = parts[4].parse::()?; 87 | let pathname = if parts.len() > 5 { 88 | parts[5].to_string() 89 | } else { 90 | String::new() 91 | }; 92 | 93 | mappings.push(MemoryMapping { 94 | start, 95 | end, 96 | permissions, 97 | offset, 98 | device, 99 | inode, 100 | pathname, 101 | }); 102 | } 103 | } 104 | 105 | Ok(mappings) 106 | } 107 | 108 | fn get_linker_base(&self) -> Result { 109 | let mappings = self.parse_proc_maps()?; 110 | 111 | for mapping in mappings { 112 | if mapping.pathname.contains("linker64") { 113 | return Ok(mapping.start); 114 | } 115 | } 116 | 117 | Err(anyhow!("Could not find linker64 in process maps")) 118 | } 119 | 120 | fn get_target_mapping(&self) -> Result<(u64, u64)> { 121 | let mappings = self.parse_proc_maps()?; 122 | let mut target_start = None; 123 | let mut target_end = None; 124 | 125 | for mapping in &mappings { 126 | if mapping.pathname.contains(&self.target_name) { 127 | if target_start.is_none() { 128 | target_start = Some(mapping.start); 129 | } 130 | target_end = Some(mapping.end); 131 | } 132 | } 133 | 134 | match (target_start, target_end) { 135 | (Some(start), Some(end)) => { 136 | if start > 0x7fffffff { 137 | Ok((start, end)) 138 | } else { 139 | Err(anyhow!("Target SO is 32-bit (base: {:#x}), only 64-bit SO files are supported. 32-bit SO files have base addresses below 0x80000000.", start)) 140 | } 141 | } 142 | _ => Err(anyhow!( 143 | "Could not find target {} in process maps", 144 | self.target_name 145 | )), 146 | } 147 | } 148 | 149 | fn read_process_memory(&self, address: u64, size: usize) -> Result> { 150 | let mem_path = format!("/proc/{}/mem", self.target_pid); 151 | let mut file = File::open(&mem_path)?; 152 | file.seek(SeekFrom::Start(address))?; 153 | 154 | let mut buffer = vec![0u8; size]; 155 | file.read_exact(&mut buffer)?; 156 | 157 | Ok(buffer) 158 | } 159 | 160 | fn get_solist_head(&self, solist_addr: u64) -> Result { 161 | let data = self.read_process_memory(solist_addr, 8)?; 162 | let mut cursor = std::io::Cursor::new(data); 163 | let solist_head = cursor.read_u64::()?; 164 | 165 | println!("[*] solist head: {:#x}", solist_head); 166 | Ok(solist_head) 167 | } 168 | 169 | fn parse_soinfo(&self, soinfo_addr: u64) -> Result { 170 | let data = self.read_process_memory(soinfo_addr, 256)?; 171 | 172 | const PTR_SIZE: usize = 8; 173 | const OFF_BASE: usize = 0x10; 174 | const OFF_SIZE: usize = 0x18; 175 | const OFF_NEXT: usize = 0x28; 176 | 177 | let mut cursor = std::io::Cursor::new(&data[OFF_BASE..OFF_BASE + PTR_SIZE]); 178 | let base = cursor.read_u64::()?; 179 | 180 | let mut cursor = std::io::Cursor::new(&data[OFF_SIZE..OFF_SIZE + PTR_SIZE]); 181 | let size = cursor.read_u64::()?; 182 | 183 | let mut cursor = std::io::Cursor::new(&data[OFF_NEXT..OFF_NEXT + PTR_SIZE]); 184 | let next = cursor.read_u64::()?; 185 | 186 | Ok(SoInfo { base, size, next }) 187 | } 188 | 189 | fn find_target_soinfo(&self, solist_head: u64, target_base: u64) -> Result { 190 | let mut current_soinfo = solist_head; 191 | let mut iteration_count = 0; 192 | const MAX_ITERATIONS: usize = 1000; 193 | 194 | while current_soinfo != 0 && iteration_count < MAX_ITERATIONS { 195 | let soinfo = self.parse_soinfo(current_soinfo)?; 196 | 197 | println!( 198 | "[*] soinfo base: {:#x}, size: {:#x}, next: {:#x}", 199 | soinfo.base, soinfo.size, soinfo.next 200 | ); 201 | 202 | if soinfo.base == target_base { 203 | return Ok(soinfo.size); 204 | } 205 | 206 | current_soinfo = soinfo.next; 207 | iteration_count += 1; 208 | } 209 | 210 | Err(anyhow!("Could not find target SO in soinfo chain")) 211 | } 212 | 213 | fn search_soinfo_chain(&self, solist_head: u64, target_base: u64) -> Result { 214 | let chain_data = self.read_process_memory(solist_head, 256 * 1024)?; 215 | 216 | let target_pattern = target_base.to_le_bytes(); 217 | 218 | for window in chain_data.windows(target_pattern.len()) { 219 | if window == target_pattern { 220 | let offset = window.as_ptr() as usize - chain_data.as_ptr() as usize + 8; 221 | if offset + 8 <= chain_data.len() { 222 | let mut cursor = std::io::Cursor::new(&chain_data[offset..offset + 8]); 223 | if let Ok(size) = cursor.read_u64::() { 224 | println!("[+] Found soinfo size: {}", size); 225 | return Ok(size); 226 | } 227 | } 228 | } 229 | } 230 | 231 | Err(anyhow!("Could not find target base in soinfo chain data")) 232 | } 233 | 234 | fn dump_so(&self, target_base: u64, so_size: u64) -> Result { 235 | println!("[+] Dumping SO from {:#x}, size: {}", target_base, so_size); 236 | 237 | let data = self.read_process_memory(target_base, so_size as usize)?; 238 | 239 | let base_name = Path::new(&self.target_name) 240 | .file_stem() 241 | .unwrap_or_default() 242 | .to_string_lossy(); 243 | 244 | let output_filename = format!("{}_{:#x}_{}_dump.so", base_name, target_base, so_size); 245 | let output_path = self.output_dir.join(&output_filename); 246 | 247 | let mut output_file = File::create(&output_path)?; 248 | output_file.write_all(&data)?; 249 | 250 | println!("[+] SO dumped to: {}", output_path.display()); 251 | 252 | if self.auto_fix { 253 | if let Err(e) = self.auto_fix_so(target_base, &output_path) { 254 | eprintln!("[!] Auto-fix failed: {}, but SO dump succeeded", e); 255 | } 256 | } 257 | 258 | Ok(output_path) 259 | } 260 | 261 | fn auto_fix_so(&self, target_base: u64, so_path: &Path) -> Result<()> { 262 | let so_name = so_path 263 | .file_name() 264 | .ok_or_else(|| anyhow!("Invalid SO path"))? 265 | .to_string_lossy(); 266 | 267 | let fixed_path = format!("{}.fix.so", so_name); 268 | let fixed_output_path = self.output_dir.join(&fixed_path); 269 | 270 | println!("[+] Auto-fixing SO file: {}", so_name); 271 | 272 | self.sofixer.extract()?; 273 | 274 | self.sofixer.fix_so( 275 | target_base, 276 | &so_path.to_string_lossy(), 277 | &fixed_output_path.to_string_lossy(), 278 | )?; 279 | 280 | Ok(()) 281 | } 282 | 283 | pub fn dump(&self) -> Result<()> { 284 | println!( 285 | "[+] Starting SO dump process for target: {}", 286 | self.target_name 287 | ); 288 | println!("[+] Target PID: {}", self.target_pid); 289 | println!("[+] Architecture: 64-bit only (ARM64/x86_64)"); 290 | 291 | if self.auto_fix { 292 | println!("[+] Extracting SoFixer binary..."); 293 | self.extract_sofixer()?; 294 | } 295 | 296 | let solist_offset = self.get_solist_offset()?; 297 | println!("[+] solist offset: {:#x}", solist_offset); 298 | 299 | self.stop_process()?; 300 | 301 | let result = (|| -> Result<()> { 302 | let linker_base = self.get_linker_base()?; 303 | println!("[+] linker64 base: {:#x}", linker_base); 304 | 305 | let (target_base, target_end) = self.get_target_mapping()?; 306 | let target_size = target_end - target_base; 307 | println!( 308 | "[+] target base: {:#x}, end: {:#x}, size: {}", 309 | target_base, target_end, target_size 310 | ); 311 | 312 | let solist_addr = linker_base + solist_offset; 313 | println!("[+] solist addr: {:#x}", solist_addr); 314 | 315 | let solist_head = self.get_solist_head(solist_addr)?; 316 | 317 | let so_size = match self.find_target_soinfo(solist_head, target_base) { 318 | Ok(size) => { 319 | if size > target_size * 10 { 320 | println!("[*] soinfo size too large, using target_size"); 321 | target_size 322 | } else { 323 | size 324 | } 325 | } 326 | Err(_) => { 327 | println!("[*] Could not find in soinfo chain, trying backup search method"); 328 | match self.search_soinfo_chain(solist_head, target_base) { 329 | Ok(size) => { 330 | if size > target_size * 10 { 331 | println!("[*] backup search size too large, using target_size"); 332 | target_size 333 | } else { 334 | size 335 | } 336 | } 337 | Err(_) => { 338 | println!("[*] Backup search failed, using target_size"); 339 | target_size 340 | } 341 | } 342 | } 343 | }; 344 | 345 | let _dump_path = self.dump_so(target_base, so_size)?; 346 | 347 | Ok(()) 348 | })(); 349 | 350 | self.continue_process()?; 351 | 352 | result 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /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 = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "android_log-sys" 16 | version = "0.3.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" 19 | 20 | [[package]] 21 | name = "android_logger" 22 | version = "0.13.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f" 25 | dependencies = [ 26 | "android_log-sys", 27 | "env_logger 0.10.2", 28 | "log", 29 | "once_cell", 30 | ] 31 | 32 | [[package]] 33 | name = "ansi_term" 34 | version = "0.12.1" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 37 | dependencies = [ 38 | "winapi", 39 | ] 40 | 41 | [[package]] 42 | name = "anstream" 43 | version = "0.6.20" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" 46 | dependencies = [ 47 | "anstyle", 48 | "anstyle-parse", 49 | "anstyle-query", 50 | "anstyle-wincon", 51 | "colorchoice", 52 | "is_terminal_polyfill", 53 | "utf8parse", 54 | ] 55 | 56 | [[package]] 57 | name = "anstyle" 58 | version = "1.0.11" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" 61 | 62 | [[package]] 63 | name = "anstyle-parse" 64 | version = "0.2.7" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 67 | dependencies = [ 68 | "utf8parse", 69 | ] 70 | 71 | [[package]] 72 | name = "anstyle-query" 73 | version = "1.1.4" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" 76 | dependencies = [ 77 | "windows-sys 0.60.2", 78 | ] 79 | 80 | [[package]] 81 | name = "anstyle-wincon" 82 | version = "3.0.10" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" 85 | dependencies = [ 86 | "anstyle", 87 | "once_cell_polyfill", 88 | "windows-sys 0.60.2", 89 | ] 90 | 91 | [[package]] 92 | name = "anyhow" 93 | version = "1.0.99" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" 96 | 97 | [[package]] 98 | name = "atty" 99 | version = "0.2.14" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 102 | dependencies = [ 103 | "hermit-abi 0.1.19", 104 | "libc", 105 | "winapi", 106 | ] 107 | 108 | [[package]] 109 | name = "autocfg" 110 | version = "1.5.0" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 113 | 114 | [[package]] 115 | name = "bindgen" 116 | version = "0.59.2" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" 119 | dependencies = [ 120 | "bitflags 1.3.2", 121 | "cexpr", 122 | "clang-sys", 123 | "clap 2.34.0", 124 | "env_logger 0.9.3", 125 | "lazy_static", 126 | "lazycell", 127 | "log", 128 | "peeking_take_while", 129 | "proc-macro2", 130 | "quote", 131 | "regex", 132 | "rustc-hash", 133 | "shlex", 134 | "which", 135 | ] 136 | 137 | [[package]] 138 | name = "bitflags" 139 | version = "1.3.2" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 142 | 143 | [[package]] 144 | name = "bitflags" 145 | version = "2.9.3" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" 148 | 149 | [[package]] 150 | name = "bumpalo" 151 | version = "3.19.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" 154 | 155 | [[package]] 156 | name = "byteorder" 157 | version = "1.5.0" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 160 | 161 | [[package]] 162 | name = "cc" 163 | version = "1.2.34" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" 166 | dependencies = [ 167 | "shlex", 168 | ] 169 | 170 | [[package]] 171 | name = "cexpr" 172 | version = "0.6.0" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 175 | dependencies = [ 176 | "nom", 177 | ] 178 | 179 | [[package]] 180 | name = "cfg-if" 181 | version = "1.0.3" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" 184 | 185 | [[package]] 186 | name = "clang-sys" 187 | version = "1.8.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 190 | dependencies = [ 191 | "glob", 192 | "libc", 193 | "libloading", 194 | ] 195 | 196 | [[package]] 197 | name = "clap" 198 | version = "2.34.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 201 | dependencies = [ 202 | "ansi_term", 203 | "atty", 204 | "bitflags 1.3.2", 205 | "strsim 0.8.0", 206 | "textwrap", 207 | "unicode-width 0.1.14", 208 | "vec_map", 209 | ] 210 | 211 | [[package]] 212 | name = "clap" 213 | version = "4.5.45" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" 216 | dependencies = [ 217 | "clap_builder", 218 | "clap_derive", 219 | ] 220 | 221 | [[package]] 222 | name = "clap_builder" 223 | version = "4.5.44" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" 226 | dependencies = [ 227 | "anstream", 228 | "anstyle", 229 | "clap_lex", 230 | "strsim 0.11.1", 231 | ] 232 | 233 | [[package]] 234 | name = "clap_derive" 235 | version = "4.5.45" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" 238 | dependencies = [ 239 | "heck", 240 | "proc-macro2", 241 | "quote", 242 | "syn", 243 | ] 244 | 245 | [[package]] 246 | name = "clap_lex" 247 | version = "0.7.5" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" 250 | 251 | [[package]] 252 | name = "colorchoice" 253 | version = "1.0.4" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 256 | 257 | [[package]] 258 | name = "console" 259 | version = "0.15.11" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" 262 | dependencies = [ 263 | "encode_unicode", 264 | "libc", 265 | "once_cell", 266 | "unicode-width 0.2.1", 267 | "windows-sys 0.59.0", 268 | ] 269 | 270 | [[package]] 271 | name = "either" 272 | version = "1.15.0" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 275 | 276 | [[package]] 277 | name = "encode_unicode" 278 | version = "1.0.0" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" 281 | 282 | [[package]] 283 | name = "env_logger" 284 | version = "0.9.3" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" 287 | dependencies = [ 288 | "atty", 289 | "humantime", 290 | "log", 291 | "regex", 292 | "termcolor", 293 | ] 294 | 295 | [[package]] 296 | name = "env_logger" 297 | version = "0.10.2" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" 300 | dependencies = [ 301 | "humantime", 302 | "is-terminal", 303 | "log", 304 | "regex", 305 | "termcolor", 306 | ] 307 | 308 | [[package]] 309 | name = "errno" 310 | version = "0.2.8" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" 313 | dependencies = [ 314 | "errno-dragonfly", 315 | "libc", 316 | "winapi", 317 | ] 318 | 319 | [[package]] 320 | name = "errno" 321 | version = "0.3.13" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" 324 | dependencies = [ 325 | "libc", 326 | "windows-sys 0.60.2", 327 | ] 328 | 329 | [[package]] 330 | name = "errno-dragonfly" 331 | version = "0.1.2" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 334 | dependencies = [ 335 | "cc", 336 | "libc", 337 | ] 338 | 339 | [[package]] 340 | name = "glob" 341 | version = "0.3.3" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" 344 | 345 | [[package]] 346 | name = "goblin" 347 | version = "0.8.2" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" 350 | dependencies = [ 351 | "log", 352 | "plain", 353 | "scroll", 354 | ] 355 | 356 | [[package]] 357 | name = "heck" 358 | version = "0.5.0" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 361 | 362 | [[package]] 363 | name = "hermit-abi" 364 | version = "0.1.19" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 367 | dependencies = [ 368 | "libc", 369 | ] 370 | 371 | [[package]] 372 | name = "hermit-abi" 373 | version = "0.5.2" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 376 | 377 | [[package]] 378 | name = "home" 379 | version = "0.5.11" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" 382 | dependencies = [ 383 | "windows-sys 0.59.0", 384 | ] 385 | 386 | [[package]] 387 | name = "humantime" 388 | version = "2.2.0" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" 391 | 392 | [[package]] 393 | name = "indicatif" 394 | version = "0.17.11" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" 397 | dependencies = [ 398 | "console", 399 | "number_prefix", 400 | "portable-atomic", 401 | "unicode-width 0.2.1", 402 | "web-time", 403 | ] 404 | 405 | [[package]] 406 | name = "is-terminal" 407 | version = "0.4.16" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" 410 | dependencies = [ 411 | "hermit-abi 0.5.2", 412 | "libc", 413 | "windows-sys 0.59.0", 414 | ] 415 | 416 | [[package]] 417 | name = "is_terminal_polyfill" 418 | version = "1.70.1" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 421 | 422 | [[package]] 423 | name = "js-sys" 424 | version = "0.3.77" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 427 | dependencies = [ 428 | "once_cell", 429 | "wasm-bindgen", 430 | ] 431 | 432 | [[package]] 433 | name = "lazy_static" 434 | version = "1.5.0" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 437 | 438 | [[package]] 439 | name = "lazycell" 440 | version = "1.3.0" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 443 | 444 | [[package]] 445 | name = "libc" 446 | version = "0.2.175" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" 449 | 450 | [[package]] 451 | name = "libloading" 452 | version = "0.8.8" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" 455 | dependencies = [ 456 | "cfg-if", 457 | "windows-targets 0.53.3", 458 | ] 459 | 460 | [[package]] 461 | name = "libproc" 462 | version = "0.10.0" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "6466fc1f834276563fbbd4be1c24236ef92bb9efdbd4691e07f1cf85a0b407f0" 465 | dependencies = [ 466 | "errno 0.2.8", 467 | "libc", 468 | ] 469 | 470 | [[package]] 471 | name = "linux-raw-sys" 472 | version = "0.4.15" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 475 | 476 | [[package]] 477 | name = "log" 478 | version = "0.4.27" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 481 | 482 | [[package]] 483 | name = "mach2" 484 | version = "0.4.3" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" 487 | dependencies = [ 488 | "libc", 489 | ] 490 | 491 | [[package]] 492 | name = "memchr" 493 | version = "2.7.5" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 496 | 497 | [[package]] 498 | name = "memoffset" 499 | version = "0.7.1" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" 502 | dependencies = [ 503 | "autocfg", 504 | ] 505 | 506 | [[package]] 507 | name = "minimal-lexical" 508 | version = "0.2.1" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 511 | 512 | [[package]] 513 | name = "nix" 514 | version = "0.26.4" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" 517 | dependencies = [ 518 | "bitflags 1.3.2", 519 | "cfg-if", 520 | "libc", 521 | "memoffset", 522 | "pin-utils", 523 | ] 524 | 525 | [[package]] 526 | name = "nom" 527 | version = "7.1.3" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 530 | dependencies = [ 531 | "memchr", 532 | "minimal-lexical", 533 | ] 534 | 535 | [[package]] 536 | name = "number_prefix" 537 | version = "0.4.0" 538 | source = "registry+https://github.com/rust-lang/crates.io-index" 539 | checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" 540 | 541 | [[package]] 542 | name = "once_cell" 543 | version = "1.21.3" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 546 | 547 | [[package]] 548 | name = "once_cell_polyfill" 549 | version = "1.70.1" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 552 | 553 | [[package]] 554 | name = "peeking_take_while" 555 | version = "0.1.2" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 558 | 559 | [[package]] 560 | name = "pin-utils" 561 | version = "0.1.0" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 564 | 565 | [[package]] 566 | name = "plain" 567 | version = "0.2.3" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 570 | 571 | [[package]] 572 | name = "portable-atomic" 573 | version = "1.11.1" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" 576 | 577 | [[package]] 578 | name = "proc-macro2" 579 | version = "1.0.101" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 582 | dependencies = [ 583 | "unicode-ident", 584 | ] 585 | 586 | [[package]] 587 | name = "proc-maps" 588 | version = "0.2.1" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "a2f62c16ccc63ce2f590b17b8b9b33616f59631b8982ad52ed21e7f6d936c409" 591 | dependencies = [ 592 | "anyhow", 593 | "bindgen", 594 | "libc", 595 | "libproc", 596 | "mach2", 597 | "winapi", 598 | ] 599 | 600 | [[package]] 601 | name = "quote" 602 | version = "1.0.40" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 605 | dependencies = [ 606 | "proc-macro2", 607 | ] 608 | 609 | [[package]] 610 | name = "regex" 611 | version = "1.11.1" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 614 | dependencies = [ 615 | "aho-corasick", 616 | "memchr", 617 | "regex-automata", 618 | "regex-syntax", 619 | ] 620 | 621 | [[package]] 622 | name = "regex-automata" 623 | version = "0.4.9" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 626 | dependencies = [ 627 | "aho-corasick", 628 | "memchr", 629 | "regex-syntax", 630 | ] 631 | 632 | [[package]] 633 | name = "regex-syntax" 634 | version = "0.8.5" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 637 | 638 | [[package]] 639 | name = "rustc-hash" 640 | version = "1.1.0" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 643 | 644 | [[package]] 645 | name = "rustix" 646 | version = "0.38.44" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 649 | dependencies = [ 650 | "bitflags 2.9.3", 651 | "errno 0.3.13", 652 | "libc", 653 | "linux-raw-sys", 654 | "windows-sys 0.59.0", 655 | ] 656 | 657 | [[package]] 658 | name = "scroll" 659 | version = "0.12.0" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" 662 | dependencies = [ 663 | "scroll_derive", 664 | ] 665 | 666 | [[package]] 667 | name = "scroll_derive" 668 | version = "0.12.1" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" 671 | dependencies = [ 672 | "proc-macro2", 673 | "quote", 674 | "syn", 675 | ] 676 | 677 | [[package]] 678 | name = "shlex" 679 | version = "1.3.0" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 682 | 683 | [[package]] 684 | name = "strsim" 685 | version = "0.8.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 688 | 689 | [[package]] 690 | name = "strsim" 691 | version = "0.11.1" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 694 | 695 | [[package]] 696 | name = "syn" 697 | version = "2.0.106" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 700 | dependencies = [ 701 | "proc-macro2", 702 | "quote", 703 | "unicode-ident", 704 | ] 705 | 706 | [[package]] 707 | name = "termcolor" 708 | version = "1.4.1" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 711 | dependencies = [ 712 | "winapi-util", 713 | ] 714 | 715 | [[package]] 716 | name = "textwrap" 717 | version = "0.11.0" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 720 | dependencies = [ 721 | "unicode-width 0.1.14", 722 | ] 723 | 724 | [[package]] 725 | name = "thiserror" 726 | version = "1.0.69" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 729 | dependencies = [ 730 | "thiserror-impl", 731 | ] 732 | 733 | [[package]] 734 | name = "thiserror-impl" 735 | version = "1.0.69" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 738 | dependencies = [ 739 | "proc-macro2", 740 | "quote", 741 | "syn", 742 | ] 743 | 744 | [[package]] 745 | name = "tinydump" 746 | version = "0.1.0" 747 | dependencies = [ 748 | "android_logger", 749 | "anyhow", 750 | "byteorder", 751 | "clap 4.5.45", 752 | "env_logger 0.10.2", 753 | "goblin", 754 | "indicatif", 755 | "log", 756 | "nix", 757 | "proc-maps", 758 | "regex", 759 | "thiserror", 760 | ] 761 | 762 | [[package]] 763 | name = "unicode-ident" 764 | version = "1.0.18" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 767 | 768 | [[package]] 769 | name = "unicode-width" 770 | version = "0.1.14" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 773 | 774 | [[package]] 775 | name = "unicode-width" 776 | version = "0.2.1" 777 | source = "registry+https://github.com/rust-lang/crates.io-index" 778 | checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" 779 | 780 | [[package]] 781 | name = "utf8parse" 782 | version = "0.2.2" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 785 | 786 | [[package]] 787 | name = "vec_map" 788 | version = "0.8.2" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 791 | 792 | [[package]] 793 | name = "wasm-bindgen" 794 | version = "0.2.100" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 797 | dependencies = [ 798 | "cfg-if", 799 | "once_cell", 800 | "wasm-bindgen-macro", 801 | ] 802 | 803 | [[package]] 804 | name = "wasm-bindgen-backend" 805 | version = "0.2.100" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 808 | dependencies = [ 809 | "bumpalo", 810 | "log", 811 | "proc-macro2", 812 | "quote", 813 | "syn", 814 | "wasm-bindgen-shared", 815 | ] 816 | 817 | [[package]] 818 | name = "wasm-bindgen-macro" 819 | version = "0.2.100" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 822 | dependencies = [ 823 | "quote", 824 | "wasm-bindgen-macro-support", 825 | ] 826 | 827 | [[package]] 828 | name = "wasm-bindgen-macro-support" 829 | version = "0.2.100" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 832 | dependencies = [ 833 | "proc-macro2", 834 | "quote", 835 | "syn", 836 | "wasm-bindgen-backend", 837 | "wasm-bindgen-shared", 838 | ] 839 | 840 | [[package]] 841 | name = "wasm-bindgen-shared" 842 | version = "0.2.100" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 845 | dependencies = [ 846 | "unicode-ident", 847 | ] 848 | 849 | [[package]] 850 | name = "web-time" 851 | version = "1.1.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 854 | dependencies = [ 855 | "js-sys", 856 | "wasm-bindgen", 857 | ] 858 | 859 | [[package]] 860 | name = "which" 861 | version = "4.4.2" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 864 | dependencies = [ 865 | "either", 866 | "home", 867 | "once_cell", 868 | "rustix", 869 | ] 870 | 871 | [[package]] 872 | name = "winapi" 873 | version = "0.3.9" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 876 | dependencies = [ 877 | "winapi-i686-pc-windows-gnu", 878 | "winapi-x86_64-pc-windows-gnu", 879 | ] 880 | 881 | [[package]] 882 | name = "winapi-i686-pc-windows-gnu" 883 | version = "0.4.0" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 886 | 887 | [[package]] 888 | name = "winapi-util" 889 | version = "0.1.10" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" 892 | dependencies = [ 893 | "windows-sys 0.60.2", 894 | ] 895 | 896 | [[package]] 897 | name = "winapi-x86_64-pc-windows-gnu" 898 | version = "0.4.0" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 901 | 902 | [[package]] 903 | name = "windows-link" 904 | version = "0.1.3" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" 907 | 908 | [[package]] 909 | name = "windows-sys" 910 | version = "0.59.0" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 913 | dependencies = [ 914 | "windows-targets 0.52.6", 915 | ] 916 | 917 | [[package]] 918 | name = "windows-sys" 919 | version = "0.60.2" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 922 | dependencies = [ 923 | "windows-targets 0.53.3", 924 | ] 925 | 926 | [[package]] 927 | name = "windows-targets" 928 | version = "0.52.6" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 931 | dependencies = [ 932 | "windows_aarch64_gnullvm 0.52.6", 933 | "windows_aarch64_msvc 0.52.6", 934 | "windows_i686_gnu 0.52.6", 935 | "windows_i686_gnullvm 0.52.6", 936 | "windows_i686_msvc 0.52.6", 937 | "windows_x86_64_gnu 0.52.6", 938 | "windows_x86_64_gnullvm 0.52.6", 939 | "windows_x86_64_msvc 0.52.6", 940 | ] 941 | 942 | [[package]] 943 | name = "windows-targets" 944 | version = "0.53.3" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" 947 | dependencies = [ 948 | "windows-link", 949 | "windows_aarch64_gnullvm 0.53.0", 950 | "windows_aarch64_msvc 0.53.0", 951 | "windows_i686_gnu 0.53.0", 952 | "windows_i686_gnullvm 0.53.0", 953 | "windows_i686_msvc 0.53.0", 954 | "windows_x86_64_gnu 0.53.0", 955 | "windows_x86_64_gnullvm 0.53.0", 956 | "windows_x86_64_msvc 0.53.0", 957 | ] 958 | 959 | [[package]] 960 | name = "windows_aarch64_gnullvm" 961 | version = "0.52.6" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 964 | 965 | [[package]] 966 | name = "windows_aarch64_gnullvm" 967 | version = "0.53.0" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 970 | 971 | [[package]] 972 | name = "windows_aarch64_msvc" 973 | version = "0.52.6" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 976 | 977 | [[package]] 978 | name = "windows_aarch64_msvc" 979 | version = "0.53.0" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 982 | 983 | [[package]] 984 | name = "windows_i686_gnu" 985 | version = "0.52.6" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 988 | 989 | [[package]] 990 | name = "windows_i686_gnu" 991 | version = "0.53.0" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 994 | 995 | [[package]] 996 | name = "windows_i686_gnullvm" 997 | version = "0.52.6" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1000 | 1001 | [[package]] 1002 | name = "windows_i686_gnullvm" 1003 | version = "0.53.0" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 1006 | 1007 | [[package]] 1008 | name = "windows_i686_msvc" 1009 | version = "0.52.6" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1012 | 1013 | [[package]] 1014 | name = "windows_i686_msvc" 1015 | version = "0.53.0" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 1018 | 1019 | [[package]] 1020 | name = "windows_x86_64_gnu" 1021 | version = "0.52.6" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1024 | 1025 | [[package]] 1026 | name = "windows_x86_64_gnu" 1027 | version = "0.53.0" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 1030 | 1031 | [[package]] 1032 | name = "windows_x86_64_gnullvm" 1033 | version = "0.52.6" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1036 | 1037 | [[package]] 1038 | name = "windows_x86_64_gnullvm" 1039 | version = "0.53.0" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 1042 | 1043 | [[package]] 1044 | name = "windows_x86_64_msvc" 1045 | version = "0.52.6" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1048 | 1049 | [[package]] 1050 | name = "windows_x86_64_msvc" 1051 | version = "0.53.0" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 1054 | --------------------------------------------------------------------------------