├── .gitignore ├── src ├── engine │ ├── mod.rs │ ├── cpu.rs │ └── machine.rs └── main.rs ├── images └── x64.png ├── readme.md ├── Cargo.toml ├── LICENSE ├── CODE_OF_CONDUCT.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | target 3 | -------------------------------------------------------------------------------- /src/engine/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cpu; 2 | pub mod machine; 3 | -------------------------------------------------------------------------------- /images/x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cch123/asm-cli-rust/HEAD/images/x64.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | this project is inspired by https://github.com/poppycompass/asmshell 4 | 5 | ## Preview 6 | 7 | ![x64](images/x64.png) 8 | 9 | ## Usage 10 | ``` 11 | shell> asm-cli-rust [x86/x64] 12 | 13 | default : x64 14 | optional: x86 15 | ``` 16 | 17 | key_up/key_down: history 18 | 19 | ## Build from source 20 | 21 | 1. `cargo b` 22 | 23 | ## Go version 24 | 25 | https://github.com/cch123/asm-cli 26 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "asm-cli-rust" 3 | version = "0.1.0" 4 | authors = ["Xargin "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | capstone = "^0.9.0" 9 | keystone = {git = "https://github.com/keystone-engine/keystone/", rev = "18569351000cf1b8bd1ea2cc8a02c2e17b76391f"} 10 | unicorn-engine = {git = "https://github.com/unicorn-engine/unicorn/", rev = "8fb4b45f57557eb82a165ec24ed8a2aa2f9f201b"} 11 | hex = "0.3.2" 12 | rustyline = "9.1.0" 13 | ansi_term = "0.11.0" 14 | maplit = "1" 15 | lazy_static = "1.4.0" 16 | clap = { version = "4.0.26", features = ["derive"] } 17 | proc-macro2 = { version = "=1.0.93", features=["default", "proc-macro"] } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Star And Thank Author License (SATA) 2 | 3 | Copyright © 2018 Xargin(cao1988228@163.com) 4 | 5 | Project Url: https://github.com/cch123/asm-cli-rust 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | And wait, the most important, you shall star/+1/like the project(s) in project url 18 | section above first, and then thank the author(s) in Copyright section. 19 | 20 | Here are some suggested ways: 21 | 22 | - Email the authors a thank-you letter, and make friends with him/her/them. 23 | - Report bugs or issues. 24 | - Tell friends what a wonderful project this is. 25 | - And, sure, you can just express thanks in your mind without telling the world. 26 | 27 | Contributors of this project by forking have the option to add his/her name and 28 | forked project url at copyright and project url sections, but shall not delete 29 | or modify anything else in these two sections. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 37 | THE SOFTWARE. 38 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at cao1988228@163.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use ansi_term::Colour::Red; 2 | use clap::Parser; 3 | use keystone::{OptionType, OptionValue, Error}; 4 | use crate::engine::machine::MachineError; 5 | use rustyline::error::ReadlineError; 6 | use rustyline::{Cmd, Editor, KeyCode, KeyEvent, Modifiers}; 7 | use unicorn_engine::unicorn_const::Permission; 8 | 9 | pub mod engine; 10 | 11 | use crate::engine::machine::Machine; 12 | 13 | #[derive(clap::ValueEnum, Clone, Debug, PartialEq)] 14 | #[allow(clippy::upper_case_acronyms)] 15 | 16 | enum AssemblerSyntax { 17 | INTEL, 18 | ATT, 19 | GAS, 20 | MASM, 21 | NASM, 22 | } 23 | 24 | #[derive(clap::Parser, Debug)] 25 | struct Args { 26 | #[arg(short, long)] 27 | arch: Option, 28 | 29 | #[arg(short, long, value_enum)] 30 | syntax: Option, 31 | 32 | #[arg(long, default_value_t = 0x01300000)] 33 | initial_sp: u64, 34 | #[arg(long, default_value_t = 0x10000000)] 35 | initial_fp: u64, 36 | 37 | #[arg(long, default_value_t = 0)] 38 | initial_mem_begin: u64, 39 | #[arg(long, default_value_t = 0x20000000)] 40 | initial_mem_size: usize, 41 | 42 | #[arg(long, default_value_t = String::from("ALL"))] 43 | initial_mem_prot: String, 44 | } 45 | 46 | fn get_machine(arch_name: String) -> Machine<'static> { 47 | Machine::new_from_arch(arch_name.as_str()).unwrap() 48 | } 49 | 50 | fn parse_permission(prot: &str) -> Permission { 51 | match prot { 52 | "READ" => Permission::READ, 53 | "WRITE" => Permission::WRITE, 54 | "EXEC" => Permission::EXEC, 55 | "NONE" => Permission::NONE, 56 | _ => Permission::ALL, 57 | } 58 | } 59 | 60 | fn main() { 61 | // let args: Vec = env::args().collect(); 62 | let args = Args::parse(); 63 | 64 | let arch_name = match args.arch { 65 | Some(r) => r, 66 | None => "x64".to_string(), 67 | }; 68 | let ass_syntax = match args.syntax { 69 | Some(syntax) => match syntax { 70 | AssemblerSyntax::INTEL => OptionValue::SYNTAX_INTEL, 71 | AssemblerSyntax::ATT => OptionValue::SYNTAX_ATT, 72 | AssemblerSyntax::GAS => OptionValue::SYNTAX_GAS, 73 | AssemblerSyntax::MASM => OptionValue::SYNTAX_MASM, 74 | AssemblerSyntax::NASM => OptionValue::SYNTAX_NASM, 75 | }, 76 | None => OptionValue::SYNTAX_INTEL, 77 | }; 78 | 79 | let mut m: Machine = get_machine(arch_name); 80 | 81 | // machine init 82 | println!("initial: sp={:?} fp={:?}", args.initial_sp, args.initial_fp); 83 | println!("ass_syntax: {:?}", ass_syntax); 84 | 85 | m.set_sp(args.initial_sp) 86 | .expect("failed to write stack pointer"); 87 | m.set_fp(args.initial_fp) 88 | .expect("failed to write stack frame"); 89 | 90 | let mem_prot = parse_permission(&args.initial_mem_prot); 91 | println!("permission: {:?}", mem_prot); 92 | m.emu 93 | .mem_map( 94 | args.initial_mem_begin, 95 | args.initial_mem_size, 96 | mem_prot, 97 | ) 98 | .expect("failed to mem map"); 99 | m.assembler 100 | .option(OptionType::SYNTAX, ass_syntax) 101 | .expect("failed to change assembler syntax"); 102 | 103 | m.print_machine(); 104 | m.print_register(); 105 | m.print_stack(); 106 | 107 | let mut rl = Editor::<()>::new(); 108 | rl.bind_sequence(KeyEvent(KeyCode::Down, Modifiers::NONE), Cmd::NextHistory); 109 | rl.bind_sequence(KeyEvent(KeyCode::Up, Modifiers::NONE), Cmd::PreviousHistory); 110 | 111 | loop { 112 | let input = rl.readline(Red.paint(">> ").to_string().as_str()); 113 | match input { 114 | Ok(line) => { 115 | let result = m.asm(line.to_string(), 0); 116 | if line.is_empty() { 117 | println!("failed to assemble, err: {:?}", Err::(MachineError::Unsupported)); 118 | } 119 | match result { 120 | Ok(r) => { 121 | rl.add_history_entry(line.as_str()); 122 | println!( 123 | "{} : {} {} : {}", 124 | Red.paint("mnemonic"), 125 | line.trim(), 126 | Red.paint("hex"), 127 | r 128 | ); 129 | m.write_instruction(r.bytes); 130 | m.print_register(); 131 | m.print_stack(); 132 | } 133 | Err(e) => println!("failed to assemble, err: {:?}", e), 134 | } 135 | } 136 | Err(ReadlineError::Interrupted) => { 137 | println!("CTRL-C"); 138 | break; 139 | } 140 | Err(ReadlineError::Eof) => { 141 | println!("CTRL-D"); 142 | break; 143 | } 144 | Err(err) => { 145 | println!("Error: {:?}", err); 146 | break; 147 | } 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/engine/cpu.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, convert::TryFrom}; 2 | 3 | use maplit::hashmap; 4 | use unicorn_engine::{unicorn_const, RegisterX86, Unicorn}; 5 | 6 | #[derive(Clone, Copy, Debug)] 7 | pub enum Mode { 8 | Mode32, 9 | Mode64, 10 | } 11 | 12 | #[allow(clippy::from_over_into)] 13 | impl Into for Mode { 14 | fn into(self) -> unicorn_const::Mode { 15 | match self { 16 | Self::Mode32 => unicorn_const::Mode::MODE_32, 17 | Self::Mode64 => unicorn_const::Mode::MODE_64, 18 | } 19 | } 20 | } 21 | 22 | #[allow(clippy::from_over_into)] 23 | impl Into for Mode { 24 | fn into(self) -> keystone::Mode { 25 | match self { 26 | Self::Mode32 => keystone::Mode::MODE_32, 27 | Self::Mode64 => keystone::Mode::MODE_64, 28 | } 29 | } 30 | } 31 | 32 | impl TryFrom for Mode { 33 | type Error = &'static str; 34 | fn try_from(value: unicorn_const::Mode) -> Result { 35 | match value { 36 | unicorn_const::Mode::MODE_32 => Ok(Self::Mode32), 37 | unicorn_const::Mode::MODE_64 => Ok(Self::Mode64), 38 | _ => Err("unsupported mode"), 39 | } 40 | } 41 | } 42 | 43 | #[derive(Clone, Copy, Debug)] 44 | pub enum Arch { 45 | X86, 46 | } 47 | 48 | #[allow(clippy::from_over_into)] 49 | impl Into for Arch { 50 | fn into(self) -> unicorn_const::Arch { 51 | match self { 52 | Self::X86 => unicorn_const::Arch::X86, 53 | } 54 | } 55 | } 56 | 57 | #[allow(clippy::from_over_into)] 58 | impl Into for Arch { 59 | fn into(self) -> keystone::Arch { 60 | match self { 61 | Self::X86 => keystone::Arch::X86, 62 | } 63 | } 64 | } 65 | 66 | impl TryFrom for Arch { 67 | type Error = &'static str; 68 | fn try_from(value: unicorn_const::Arch) -> Result { 69 | match value { 70 | unicorn_const::Arch::X86 => Ok(Self::X86), 71 | _ => Err("unsupported arch"), 72 | } 73 | } 74 | } 75 | 76 | impl Arch { 77 | fn dump_registers( 78 | &self, 79 | emu: &Unicorn<'static, ()>, 80 | registers: HashMap<&'static str, i32>, 81 | ) -> HashMap<&'static str, u64> { 82 | registers 83 | .keys() 84 | .filter(|&&x| x != "end") // "end" is pseudo-register (to add new row) 85 | .map(|®_name| { 86 | ( 87 | reg_name, 88 | emu.reg_read(*registers.get(reg_name).unwrap()).unwrap(), 89 | ) 90 | }) 91 | .collect::>() 92 | } 93 | } 94 | 95 | pub trait ArchMeta { 96 | fn cpu(&self) -> (Arch, Mode); 97 | fn sp_reg(&self) -> i32; 98 | fn fp_reg(&self) -> i32; 99 | fn int_size(&self) -> usize; 100 | fn sorted_reg_names(&self) -> Vec<&'static str>; 101 | fn register_map(&self) -> HashMap<&'static str, i32>; 102 | fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'static str, u64>; 103 | } 104 | 105 | #[derive(Clone, Copy, Debug)] 106 | pub struct X32 { 107 | inner: Arch, 108 | } 109 | impl X32 { 110 | pub fn new(arch: Arch) -> Self { 111 | Self { inner: arch } 112 | } 113 | } 114 | impl ArchMeta for X32 { 115 | fn cpu(&self) -> (Arch, Mode) { 116 | (self.inner, Mode::Mode32) 117 | } 118 | 119 | fn sp_reg(&self) -> i32 { 120 | i32::from(RegisterX86::ESP) 121 | } 122 | fn fp_reg(&self) -> i32 { 123 | i32::from(RegisterX86::EBP) 124 | } 125 | 126 | fn int_size(&self) -> usize { 127 | 32 / 8 128 | } 129 | 130 | fn sorted_reg_names(&self) -> Vec<&'static str> { 131 | vec![ 132 | "eax", "ebx", "ecx", "edx", "end", // 133 | "esi", "edi", "end", // 134 | "eip", "ebp", "esp", "end", // 135 | "flags", "end", // 136 | "cs", "ss", "ds", "es", "end", // 137 | "fs", "gs", "end", // 138 | ] 139 | } 140 | 141 | fn register_map(&self) -> HashMap<&'static str, i32> { 142 | // register to trace, display, etc. 143 | hashmap! { 144 | "eax" => i32::from(RegisterX86::EAX), 145 | "ebx" => i32::from(RegisterX86::EBX), 146 | "ecx" => i32::from(RegisterX86::ECX), 147 | "edx" => i32::from(RegisterX86::EDX), 148 | "esi" => i32::from(RegisterX86::ESI), 149 | "edi" => i32::from(RegisterX86::EDI), 150 | "eip" => i32::from(RegisterX86::EIP), 151 | "ebp" => i32::from(RegisterX86::EBP), 152 | "esp" => i32::from(RegisterX86::ESP), 153 | "flags" => i32::from(RegisterX86::EFLAGS), 154 | "cs" => i32::from(RegisterX86::CS), 155 | "ss" => i32::from(RegisterX86::SS), 156 | "ds" => i32::from(RegisterX86::DS), 157 | "es" => i32::from(RegisterX86::ES), 158 | "fs" => i32::from(RegisterX86::FS), 159 | "gs" => i32::from(RegisterX86::GS), 160 | } 161 | } 162 | 163 | fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'static str, u64> { 164 | self.inner.dump_registers(emu, self.register_map()) 165 | } 166 | } 167 | 168 | #[derive(Clone, Copy, Debug)] 169 | pub struct X64 { 170 | inner: Arch, 171 | } 172 | impl X64 { 173 | pub fn new(arch: Arch) -> X64 { 174 | X64 { inner: arch } 175 | } 176 | } 177 | impl ArchMeta for X64 { 178 | fn cpu(&self) -> (Arch, Mode) { 179 | (self.inner, Mode::Mode64) 180 | } 181 | 182 | fn sp_reg(&self) -> i32 { 183 | i32::from(RegisterX86::RSP) 184 | } 185 | fn fp_reg(&self) -> i32 { 186 | i32::from(RegisterX86::RBP) 187 | } 188 | 189 | fn int_size(&self) -> usize { 190 | 64 / 8 191 | } 192 | 193 | fn sorted_reg_names(&self) -> Vec<&'static str> { 194 | vec![ 195 | "rax", "rbx", "rcx", "rdx", "end", // 196 | "rsi", "rdi", "r8", "r9", "end", // 197 | "r10", "r11", "r12", "r13", "end", // 198 | "r14", "r15", "end", // 199 | "rip", "rbp", "rsp", "end", // 200 | "cs", "ss", "ds", "es", "end", // 201 | "fs", "gs", "end", "flags", "end", // 202 | ] 203 | } 204 | 205 | fn register_map(&self) -> HashMap<&'static str, i32> { 206 | // register to trace, display, etc. 207 | hashmap! { 208 | "rax" => i32::from(RegisterX86::RAX), 209 | "rbx" => i32::from(RegisterX86::RBX), 210 | "rcx" => i32::from(RegisterX86::RCX), 211 | "rdx" => i32::from(RegisterX86::RDX), 212 | "rsi" => i32::from(RegisterX86::RSI), 213 | "rdi" => i32::from(RegisterX86::RDI), 214 | "r8" => i32::from(RegisterX86::R8), 215 | "r9" => i32::from(RegisterX86::R9), 216 | "r10" => i32::from(RegisterX86::R10), 217 | "r11" => i32::from(RegisterX86::R11), 218 | "r12" => i32::from(RegisterX86::R12), 219 | "r13" => i32::from(RegisterX86::R13), 220 | "r14" => i32::from(RegisterX86::R14), 221 | "r15" => i32::from(RegisterX86::R15), 222 | "rip" => i32::from(RegisterX86::RIP), 223 | "rbp" => i32::from(RegisterX86::RBP), 224 | "rsp" => i32::from(RegisterX86::RSP), 225 | "flags" => i32::from(RegisterX86::EFLAGS), 226 | "cs" => i32::from(RegisterX86::CS), 227 | "ss" => i32::from(RegisterX86::SS), 228 | "ds" => i32::from(RegisterX86::DS), 229 | "es" => i32::from(RegisterX86::ES), 230 | "fs" => i32::from(RegisterX86::FS), 231 | "gs" => i32::from(RegisterX86::GS), 232 | } 233 | } 234 | 235 | fn dump_registers(&self, emu: &Unicorn<'static, ()>) -> HashMap<&'static str, u64> { 236 | self.inner.dump_registers(emu, self.register_map()) 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/engine/machine.rs: -------------------------------------------------------------------------------- 1 | use ansi_term::Colour::{Blue, Purple, Yellow}; 2 | use keystone::{AsmResult, Error}; 3 | use std::collections::HashMap; 4 | use unicorn_engine::unicorn_const::uc_error; 5 | use unicorn_engine::unicorn_const::SECOND_SCALE; 6 | use unicorn_engine::Unicorn; 7 | 8 | use super::cpu; 9 | 10 | #[derive(Debug)] 11 | pub enum MachineError { 12 | Unsupported, 13 | Keystone(keystone::Error), 14 | Unicorn(uc_error), 15 | } 16 | 17 | pub struct Machine<'a> { 18 | pub register_map: HashMap<&'a str, i32>, 19 | pub assembler: keystone::Keystone, 20 | pub emu: Unicorn<'static, ()>, 21 | pub sorted_reg_names: Vec<&'a str>, 22 | pub byte_size: usize, 23 | pub previous_reg_value: HashMap<&'a str, u64>, 24 | pub cpu: (cpu::Arch, cpu::Mode), 25 | pub sp: i32, // stack pointer 26 | pub fp: i32, // stack frame 27 | } 28 | 29 | impl<'a> Machine<'a> { 30 | pub fn new(arch: cpu::Arch, mode: cpu::Mode) -> Result { 31 | let emu = Self::init_unicorn(arch, mode)?; 32 | let assembler = Self::init_keystone(arch, mode)?; 33 | let arch_meta = Self::get_arch_meta(arch, mode)?; 34 | 35 | let register_map = arch_meta.register_map(); 36 | let prev_reg_value = arch_meta.dump_registers(&emu); 37 | 38 | Ok(Self { 39 | emu, 40 | assembler, 41 | 42 | register_map, 43 | sorted_reg_names: arch_meta.sorted_reg_names(), 44 | byte_size: arch_meta.int_size(), 45 | previous_reg_value: prev_reg_value, 46 | cpu: arch_meta.cpu(), 47 | 48 | sp: arch_meta.sp_reg(), 49 | fp: arch_meta.fp_reg(), 50 | }) 51 | } 52 | 53 | pub fn new_from_arch(arch_name: &str) -> Result { 54 | let arch_meta = Self::get_arch_meta_from_name(arch_name)?; 55 | let cpu = arch_meta.cpu(); 56 | Self::new(cpu.0, cpu.1) 57 | } 58 | 59 | pub(crate) fn init_unicorn( 60 | arch: cpu::Arch, 61 | mode: cpu::Mode, 62 | ) -> Result, MachineError> { 63 | Unicorn::new(arch.into(), mode.into()).map_err(MachineError::Unicorn) 64 | } 65 | 66 | pub(crate) fn init_keystone( 67 | arch: cpu::Arch, 68 | mode: cpu::Mode, 69 | ) -> Result { 70 | keystone::Keystone::new(arch.into(), mode.into()).map_err(MachineError::Keystone) 71 | } 72 | 73 | pub(crate) fn get_arch_name( 74 | arch: cpu::Arch, 75 | mode: cpu::Mode, 76 | ) -> Result<&'static str, MachineError> { 77 | match arch { 78 | cpu::Arch::X86 => match mode { 79 | cpu::Mode::Mode32 => Ok("x32"), 80 | cpu::Mode::Mode64 => Ok("x64"), 81 | // _ => Err(MachineError::Unsupported), 82 | }, 83 | // _ => Err(MachineError::Unsupported), 84 | } 85 | } 86 | 87 | pub(crate) fn get_arch_meta( 88 | arch: cpu::Arch, 89 | mode: cpu::Mode, 90 | ) -> Result, MachineError> { 91 | let arch_name = Self::get_arch_name(arch, mode)?; 92 | Self::get_arch_meta_from_name(arch_name) 93 | } 94 | 95 | pub(crate) fn get_arch_meta_from_name( 96 | arch_name: &str, 97 | ) -> Result, MachineError> { 98 | match arch_name { 99 | "x32" => Ok(Box::new(cpu::X32::new(cpu::Arch::X86))), 100 | "x64" => Ok(Box::new(cpu::X64::new(cpu::Arch::X86))), 101 | _ => Err(MachineError::Unsupported), 102 | } 103 | } 104 | 105 | pub fn set_sp(&mut self, value: u64) -> Result<(), MachineError> { 106 | self.emu 107 | .reg_write(self.sp, value) 108 | .map_err(MachineError::Unicorn) 109 | } 110 | pub fn set_fp(&mut self, value: u64) -> Result<(), MachineError> { 111 | self.emu 112 | .reg_write(self.fp, value) 113 | .map_err(MachineError::Unicorn) 114 | } 115 | } 116 | 117 | impl<'a> Machine<'a> { 118 | pub fn print_machine(&self) { 119 | println!("arch: {:?} mode: {:?}", self.cpu.0, self.cpu.1); 120 | } 121 | pub fn print_register(&mut self) { 122 | println!( 123 | "{}", 124 | Yellow.paint("----------------- cpu context -----------------") 125 | ); 126 | 127 | let mut current_reg_val_map = HashMap::new(); 128 | for ®_name in &self.sorted_reg_names { 129 | if reg_name == "end" { 130 | println!(); 131 | continue; 132 | } 133 | 134 | let &uc_reg = self.register_map.get(reg_name).unwrap(); 135 | 136 | // pad reg_name to 3 bytes 137 | let mut padded_reg_name = reg_name.to_string(); 138 | while padded_reg_name.len() < 3 { 139 | padded_reg_name.push(' '); 140 | } 141 | 142 | let reg_val = self.emu.reg_read(uc_reg).unwrap(); 143 | let previous_reg_val = *self.previous_reg_value.get(reg_name).unwrap(); 144 | 145 | let reg_val_str = match self.byte_size { 146 | 4 => format!("0x{:08x}", reg_val), 147 | 8 => format!("0x{:016x}", reg_val), 148 | _ => unreachable!(), 149 | }; 150 | 151 | if previous_reg_val != reg_val { 152 | print!("{} : {} ", padded_reg_name, Blue.paint(reg_val_str)); 153 | } else { 154 | print!("{} : {} ", padded_reg_name, reg_val_str); 155 | } 156 | current_reg_val_map.insert(reg_name, reg_val); 157 | if reg_name == "flags" { 158 | self.print_flags(reg_val); 159 | } 160 | } 161 | self.previous_reg_value = current_reg_val_map; 162 | } 163 | 164 | pub fn asm(&self, str: String, address: u64) -> Result { 165 | self.assembler.asm(str, address) 166 | } 167 | 168 | pub fn write_instruction(&mut self, byte_arr: Vec) { 169 | let address = 0x0000; 170 | let _ = self.emu.mem_write(address, &byte_arr); 171 | let _ = self.emu.emu_start( 172 | address, 173 | address + byte_arr.len() as u64, 174 | 10 * SECOND_SCALE, 175 | 1000, 176 | ); 177 | } 178 | 179 | pub fn print_stack(&self) { 180 | println!( 181 | "{}", 182 | Purple.paint("----------------- stack context -----------------") 183 | ); 184 | let cur_sp_val = self.emu.reg_read(self.sp).unwrap(); 185 | 186 | //let start_address = (0x1300000 - 8 * self.byte_size) as u64; 187 | let mut start_address: u64 = 0x1300000; 188 | while cur_sp_val < start_address - 4 * self.byte_size as u64 { 189 | start_address -= 4 * self.byte_size as u64; 190 | } 191 | start_address -= 8 * self.byte_size as u64; 192 | let mem_data = self 193 | .emu 194 | .mem_read_as_vec(start_address, self.byte_size * 4 * 5) 195 | .unwrap(); 196 | 197 | // 8 个字节打印一次 198 | (0..mem_data.len()) 199 | .step_by(4 * self.byte_size) 200 | .for_each(|idx| { 201 | match self.byte_size { 202 | 4 => print!("{:08x} : ", start_address + idx as u64), 203 | 8 => print!("{:016x} : ", start_address + idx as u64), 204 | _ => unreachable!(), 205 | } 206 | 207 | (0..4).for_each(|offset| { 208 | let (start_pos, end_pos) = ( 209 | idx + offset * self.byte_size, 210 | idx + offset * self.byte_size + self.byte_size, 211 | ); 212 | let mut cur = mem_data[start_pos..end_pos].to_vec(); 213 | cur.reverse(); 214 | if (start_address + start_pos as u64) == cur_sp_val { 215 | print!("{} ", Blue.paint(hex::encode(cur))); 216 | } else { 217 | print!("{} ", hex::encode(cur)); 218 | } 219 | }); 220 | println!(); 221 | }); 222 | println!(); 223 | } 224 | 225 | fn print_flags(&self, flag_val: u64) { 226 | let flag_names = vec!["cf", "zf", "of", "sf", "pf", "af", "df"]; 227 | let name_to_bit = vec![ 228 | ("cf", 0), 229 | ("pf", 2), 230 | ("af", 4), 231 | ("zf", 6), 232 | ("sf", 7), 233 | ("df", 10), 234 | ("of", 11), 235 | ] 236 | .into_iter() 237 | .collect::>(); 238 | 239 | for flag_name in flag_names { 240 | let bit_pos = name_to_bit.get(flag_name).unwrap(); 241 | let flag_val = flag_val >> (*bit_pos as u64) & 1; 242 | match flag_val { 243 | 0 => print!("{}({}) ", flag_name, flag_val), 244 | 1 => print!("{} ", Blue.paint(format!("{}({})", flag_name, flag_val))), 245 | _ => unreachable!(), 246 | } 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /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 = "ansi_term" 7 | version = "0.11.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 10 | dependencies = [ 11 | "winapi", 12 | ] 13 | 14 | [[package]] 15 | name = "asm-cli-rust" 16 | version = "0.1.0" 17 | dependencies = [ 18 | "ansi_term", 19 | "capstone", 20 | "clap", 21 | "hex", 22 | "keystone", 23 | "lazy_static", 24 | "maplit", 25 | "proc-macro2", 26 | "rustyline", 27 | "unicorn-engine", 28 | ] 29 | 30 | [[package]] 31 | name = "atty" 32 | version = "0.2.14" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 35 | dependencies = [ 36 | "hermit-abi", 37 | "libc", 38 | "winapi", 39 | ] 40 | 41 | [[package]] 42 | name = "autocfg" 43 | version = "1.1.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 46 | 47 | [[package]] 48 | name = "bitflags" 49 | version = "1.3.2" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 52 | 53 | [[package]] 54 | name = "capstone" 55 | version = "0.9.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "178b3c80b4ce3939792d1dd6600575e012da806a10e81abe812dc29cbfe629ec" 58 | dependencies = [ 59 | "capstone-sys", 60 | "libc", 61 | ] 62 | 63 | [[package]] 64 | name = "capstone-sys" 65 | version = "0.13.0" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "cf2f3d97b88fa4a9a6464c7c08b8c4588aaea8c18d0651eca11f2ca15f50f1f6" 68 | dependencies = [ 69 | "cc", 70 | "libc", 71 | ] 72 | 73 | [[package]] 74 | name = "cc" 75 | version = "1.0.73" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 78 | 79 | [[package]] 80 | name = "cfg-if" 81 | version = "1.0.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 84 | 85 | [[package]] 86 | name = "clap" 87 | version = "4.0.26" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" 90 | dependencies = [ 91 | "atty", 92 | "bitflags", 93 | "clap_derive", 94 | "clap_lex", 95 | "once_cell", 96 | "strsim", 97 | "termcolor", 98 | ] 99 | 100 | [[package]] 101 | name = "clap_derive" 102 | version = "4.0.21" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" 105 | dependencies = [ 106 | "heck", 107 | "proc-macro-error", 108 | "proc-macro2", 109 | "quote", 110 | "syn", 111 | ] 112 | 113 | [[package]] 114 | name = "clap_lex" 115 | version = "0.3.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" 118 | dependencies = [ 119 | "os_str_bytes", 120 | ] 121 | 122 | [[package]] 123 | name = "clipboard-win" 124 | version = "4.4.1" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "2f3e1238132dc01f081e1cbb9dace14e5ef4c3a51ee244bd982275fb514605db" 127 | dependencies = [ 128 | "error-code", 129 | "str-buf", 130 | "winapi", 131 | ] 132 | 133 | [[package]] 134 | name = "cmake" 135 | version = "0.1.48" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" 138 | dependencies = [ 139 | "cc", 140 | ] 141 | 142 | [[package]] 143 | name = "dirs-next" 144 | version = "2.0.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" 147 | dependencies = [ 148 | "cfg-if", 149 | "dirs-sys-next", 150 | ] 151 | 152 | [[package]] 153 | name = "dirs-sys-next" 154 | version = "0.1.2" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" 157 | dependencies = [ 158 | "libc", 159 | "redox_users", 160 | "winapi", 161 | ] 162 | 163 | [[package]] 164 | name = "endian-type" 165 | version = "0.1.2" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" 168 | 169 | [[package]] 170 | name = "errno" 171 | version = "0.2.8" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" 174 | dependencies = [ 175 | "errno-dragonfly", 176 | "libc", 177 | "winapi", 178 | ] 179 | 180 | [[package]] 181 | name = "errno-dragonfly" 182 | version = "0.1.2" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 185 | dependencies = [ 186 | "cc", 187 | "libc", 188 | ] 189 | 190 | [[package]] 191 | name = "error-code" 192 | version = "2.3.1" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" 195 | dependencies = [ 196 | "libc", 197 | "str-buf", 198 | ] 199 | 200 | [[package]] 201 | name = "fd-lock" 202 | version = "3.0.5" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "46e245f4c8ec30c6415c56cb132c07e69e74f1942f6b4a4061da748b49f486ca" 205 | dependencies = [ 206 | "cfg-if", 207 | "rustix", 208 | "windows-sys", 209 | ] 210 | 211 | [[package]] 212 | name = "getrandom" 213 | version = "0.2.6" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" 216 | dependencies = [ 217 | "cfg-if", 218 | "libc", 219 | "wasi", 220 | ] 221 | 222 | [[package]] 223 | name = "heck" 224 | version = "0.4.0" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 227 | 228 | [[package]] 229 | name = "hermit-abi" 230 | version = "0.1.19" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 233 | dependencies = [ 234 | "libc", 235 | ] 236 | 237 | [[package]] 238 | name = "hex" 239 | version = "0.3.2" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 242 | 243 | [[package]] 244 | name = "io-lifetimes" 245 | version = "0.6.1" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "9448015e586b611e5d322f6703812bbca2f1e709d5773ecd38ddb4e3bb649504" 248 | 249 | [[package]] 250 | name = "keystone" 251 | version = "0.9.2" 252 | source = "git+https://github.com/keystone-engine/keystone/?rev=18569351000cf1b8bd1ea2cc8a02c2e17b76391f#18569351000cf1b8bd1ea2cc8a02c2e17b76391f" 253 | dependencies = [ 254 | "keystone-sys", 255 | "libc", 256 | ] 257 | 258 | [[package]] 259 | name = "keystone-sys" 260 | version = "0.9.2" 261 | source = "git+https://github.com/keystone-engine/keystone/?rev=18569351000cf1b8bd1ea2cc8a02c2e17b76391f#18569351000cf1b8bd1ea2cc8a02c2e17b76391f" 262 | dependencies = [ 263 | "bitflags", 264 | "cmake", 265 | "libc", 266 | ] 267 | 268 | [[package]] 269 | name = "lazy_static" 270 | version = "1.4.0" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 273 | 274 | [[package]] 275 | name = "libc" 276 | version = "0.2.124" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" 279 | 280 | [[package]] 281 | name = "linux-raw-sys" 282 | version = "0.0.42" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" 285 | 286 | [[package]] 287 | name = "log" 288 | version = "0.4.16" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" 291 | dependencies = [ 292 | "cfg-if", 293 | ] 294 | 295 | [[package]] 296 | name = "maplit" 297 | version = "1.0.2" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 300 | 301 | [[package]] 302 | name = "memchr" 303 | version = "2.4.1" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 306 | 307 | [[package]] 308 | name = "memoffset" 309 | version = "0.6.5" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 312 | dependencies = [ 313 | "autocfg", 314 | ] 315 | 316 | [[package]] 317 | name = "nibble_vec" 318 | version = "0.1.0" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" 321 | dependencies = [ 322 | "smallvec", 323 | ] 324 | 325 | [[package]] 326 | name = "nix" 327 | version = "0.23.1" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" 330 | dependencies = [ 331 | "bitflags", 332 | "cc", 333 | "cfg-if", 334 | "libc", 335 | "memoffset", 336 | ] 337 | 338 | [[package]] 339 | name = "once_cell" 340 | version = "1.16.0" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" 343 | 344 | [[package]] 345 | name = "os_str_bytes" 346 | version = "6.4.1" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" 349 | 350 | [[package]] 351 | name = "pkg-config" 352 | version = "0.3.25" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" 355 | 356 | [[package]] 357 | name = "proc-macro-error" 358 | version = "1.0.4" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 361 | dependencies = [ 362 | "proc-macro-error-attr", 363 | "proc-macro2", 364 | "quote", 365 | "syn", 366 | "version_check", 367 | ] 368 | 369 | [[package]] 370 | name = "proc-macro-error-attr" 371 | version = "1.0.4" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 374 | dependencies = [ 375 | "proc-macro2", 376 | "quote", 377 | "version_check", 378 | ] 379 | 380 | [[package]] 381 | name = "proc-macro2" 382 | version = "1.0.93" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 385 | dependencies = [ 386 | "unicode-ident", 387 | ] 388 | 389 | [[package]] 390 | name = "quote" 391 | version = "1.0.18" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" 394 | dependencies = [ 395 | "proc-macro2", 396 | ] 397 | 398 | [[package]] 399 | name = "radix_trie" 400 | version = "0.2.1" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" 403 | dependencies = [ 404 | "endian-type", 405 | "nibble_vec", 406 | ] 407 | 408 | [[package]] 409 | name = "redox_syscall" 410 | version = "0.2.13" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 413 | dependencies = [ 414 | "bitflags", 415 | ] 416 | 417 | [[package]] 418 | name = "redox_users" 419 | version = "0.4.3" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 422 | dependencies = [ 423 | "getrandom", 424 | "redox_syscall", 425 | "thiserror", 426 | ] 427 | 428 | [[package]] 429 | name = "rustix" 430 | version = "0.34.4" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "3f5d1c6ed6d1c6915aa64749b809fc1bafff49d160f5d927463658093d7d62ab" 433 | dependencies = [ 434 | "bitflags", 435 | "errno", 436 | "io-lifetimes", 437 | "libc", 438 | "linux-raw-sys", 439 | "winapi", 440 | ] 441 | 442 | [[package]] 443 | name = "rustyline" 444 | version = "9.1.2" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039" 447 | dependencies = [ 448 | "bitflags", 449 | "cfg-if", 450 | "clipboard-win", 451 | "dirs-next", 452 | "fd-lock", 453 | "libc", 454 | "log", 455 | "memchr", 456 | "nix", 457 | "radix_trie", 458 | "scopeguard", 459 | "smallvec", 460 | "unicode-segmentation", 461 | "unicode-width", 462 | "utf8parse", 463 | "winapi", 464 | ] 465 | 466 | [[package]] 467 | name = "scopeguard" 468 | version = "1.1.0" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 471 | 472 | [[package]] 473 | name = "smallvec" 474 | version = "1.8.0" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" 477 | 478 | [[package]] 479 | name = "str-buf" 480 | version = "1.0.5" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" 483 | 484 | [[package]] 485 | name = "strsim" 486 | version = "0.10.0" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 489 | 490 | [[package]] 491 | name = "syn" 492 | version = "1.0.91" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" 495 | dependencies = [ 496 | "proc-macro2", 497 | "quote", 498 | "unicode-xid", 499 | ] 500 | 501 | [[package]] 502 | name = "termcolor" 503 | version = "1.1.3" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 506 | dependencies = [ 507 | "winapi-util", 508 | ] 509 | 510 | [[package]] 511 | name = "thiserror" 512 | version = "1.0.30" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 515 | dependencies = [ 516 | "thiserror-impl", 517 | ] 518 | 519 | [[package]] 520 | name = "thiserror-impl" 521 | version = "1.0.30" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 524 | dependencies = [ 525 | "proc-macro2", 526 | "quote", 527 | "syn", 528 | ] 529 | 530 | [[package]] 531 | name = "unicode-ident" 532 | version = "1.0.5" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" 535 | 536 | [[package]] 537 | name = "unicode-segmentation" 538 | version = "1.9.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" 541 | 542 | [[package]] 543 | name = "unicode-width" 544 | version = "0.1.9" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 547 | 548 | [[package]] 549 | name = "unicode-xid" 550 | version = "0.2.2" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 553 | 554 | [[package]] 555 | name = "unicorn-engine" 556 | version = "2.0.0-rc7" 557 | source = "git+https://github.com/unicorn-engine/unicorn/?rev=8fb4b45f57557eb82a165ec24ed8a2aa2f9f201b#8fb4b45f57557eb82a165ec24ed8a2aa2f9f201b" 558 | dependencies = [ 559 | "bitflags", 560 | "cc", 561 | "cmake", 562 | "libc", 563 | "pkg-config", 564 | ] 565 | 566 | [[package]] 567 | name = "utf8parse" 568 | version = "0.2.0" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" 571 | 572 | [[package]] 573 | name = "version_check" 574 | version = "0.9.4" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 577 | 578 | [[package]] 579 | name = "wasi" 580 | version = "0.10.2+wasi-snapshot-preview1" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 583 | 584 | [[package]] 585 | name = "winapi" 586 | version = "0.3.9" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 589 | dependencies = [ 590 | "winapi-i686-pc-windows-gnu", 591 | "winapi-x86_64-pc-windows-gnu", 592 | ] 593 | 594 | [[package]] 595 | name = "winapi-i686-pc-windows-gnu" 596 | version = "0.4.0" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 599 | 600 | [[package]] 601 | name = "winapi-util" 602 | version = "0.1.5" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 605 | dependencies = [ 606 | "winapi", 607 | ] 608 | 609 | [[package]] 610 | name = "winapi-x86_64-pc-windows-gnu" 611 | version = "0.4.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 614 | 615 | [[package]] 616 | name = "windows-sys" 617 | version = "0.30.0" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "030b7ff91626e57a05ca64a07c481973cbb2db774e4852c9c7ca342408c6a99a" 620 | dependencies = [ 621 | "windows_aarch64_msvc", 622 | "windows_i686_gnu", 623 | "windows_i686_msvc", 624 | "windows_x86_64_gnu", 625 | "windows_x86_64_msvc", 626 | ] 627 | 628 | [[package]] 629 | name = "windows_aarch64_msvc" 630 | version = "0.30.0" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" 633 | 634 | [[package]] 635 | name = "windows_i686_gnu" 636 | version = "0.30.0" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" 639 | 640 | [[package]] 641 | name = "windows_i686_msvc" 642 | version = "0.30.0" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" 645 | 646 | [[package]] 647 | name = "windows_x86_64_gnu" 648 | version = "0.30.0" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" 651 | 652 | [[package]] 653 | name = "windows_x86_64_msvc" 654 | version = "0.30.0" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" 657 | --------------------------------------------------------------------------------