From 2f819ce8543aded2a7b0f1c66daa4d1a16437a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ege=20Balc=C4=B1?= Date: Tue, 2 Jul 2024 20:55:00 +0200 Subject: [PATCH] Major code refactoring with clippy. --- Cargo.toml | 4 +- src/options.rs | 8 +- src/x86_64/deoptimizer.rs | 50 ++--- src/x86_64/helpers.rs | 143 ++++++------ src/x86_64/tests.rs | 122 +++++------ .../transforms/arithmetic_partitioning.rs | 4 +- src/x86_64/transforms/condition_expand.rs | 12 +- .../transforms/immediate_to_register.rs | 204 +++++++++--------- src/x86_64/transforms/logical_inverse.rs | 10 +- src/x86_64/transforms/logical_partitioning.rs | 28 ++- src/x86_64/transforms/mod.rs | 2 +- src/x86_64/transforms/offset_mutation.rs | 20 +- src/x86_64/transforms/register_swap.rs | 8 +- 13 files changed, 301 insertions(+), 314 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 615fa49..5e59e63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,8 @@ name = "deoptimizer" version = "0.1.0" edition = "2021" -license = "MIT OR Apache-2.0" -license-file = "LICENSE" +license = "MIT" +# license-file = "LICENSE" readme = "README.md" repository = "https://github.com/EgeBalci/deoptimizer" authors = ["Ege BALCI "] diff --git a/src/options.rs b/src/options.rs index 536f660..d2d2e72 100644 --- a/src/options.rs +++ b/src/options.rs @@ -91,7 +91,7 @@ pub fn parse_options() -> Result { // let mut opts: Options = argh::from_env(); let mut opts = Options::parse(); if opts.file.is_empty() { - print!("\n"); + println!(); error!("The '-f' parameter is mandatory.\n"); Options::command().print_help()?; process::exit(0x01); @@ -120,11 +120,11 @@ pub fn parse_options() -> Result { } pub fn parse_offset(offsets: &str) -> Result<(u32, u32), ArgParseError> { - if offsets.matches("-").count() != 1 { + if offsets.matches('-').count() != 1 { return Err(ArgParseError::InvalidOffsetValues); } let mut off: Vec = Vec::new(); - for part in offsets.split("-") { + for part in offsets.split('-') { if part.starts_with("0x") { off.push(u32::from_str_radix(part.trim_start_matches("0x"), 16)?) } else { @@ -201,5 +201,5 @@ pub fn print_summary(opts: &Options) { opts.transforms, " ".repeat(wspace - opts.transforms.len()) ); - print!("\n"); + println!(); } diff --git a/src/x86_64/deoptimizer.rs b/src/x86_64/deoptimizer.rs index 7dbde56..7cc9c3e 100644 --- a/src/x86_64/deoptimizer.rs +++ b/src/x86_64/deoptimizer.rs @@ -2,27 +2,31 @@ use crate::x86_64::*; use bitflags::bitflags; use iced_x86::code_asm::*; use iced_x86::*; -use log::{debug, error, info, trace, warn}; -use rand::{seq::SliceRandom, Rng}; +use log::{error, info, trace, warn}; +use rand::Rng; use std::collections::HashMap; use thiserror::Error; #[derive(Error, Debug)] pub enum DeoptimizerError { + // #[error("Instruction with unexpected operand count.")] + // UnexpectedOperandCount, + // #[error("Given instruction not found in code map.")] + // InstructionNotFound, + // #[error("Code analysis results are not found.")] + // MissingCodeAnalysis, + // #[error("Near branch value too large.")] + // NearBranchTooBig, + // #[error("Unexpected memory size given.")] + // UnexpectedMemorySize, + // #[error("Offset skipping failed!")] + // OffsetSkipFail, #[error("Invalid formatter syntax.")] InvalidSyntax, #[error("Invalid processor mode(bitness). (16/32/64 accepted)")] InvalidProcessorMode, - #[error("Instruction with unexpected operand count.")] - UnexpectedOperandCount, #[error("All available instruction transform gadgets failed.")] AllTransformsFailed, - #[error("Given instruction not found in code map.")] - InstructionNotFound, - #[error("Code analysis results are not found.")] - MissingCodeAnalysis, - #[error("Near branch value too large.")] - NearBranchTooBig, #[error("Far branch value too large.")] FarBranchTooBig, #[error("Found invalid instruction.")] @@ -31,8 +35,6 @@ pub enum DeoptimizerError { BracnhTargetNotFound, #[error("This transform not possible for given instruction.")] TransformNotPossible, - #[error("Unexpected memory size given.")] - UnexpectedMemorySize, #[error("Unexpected register size given.")] UnexpectedRegisterSize, #[error("Unexpected operand type encountered.")] @@ -45,8 +47,6 @@ pub enum DeoptimizerError { TransposeFailed, #[error("Invalid transform gadget.")] InvalidTransformGadget, - #[error("Offset skipping failed!")] - OffsetSkipFail, #[error("Instruction encoding failed: {0}")] EncodingFail(#[from] IcedError), } @@ -58,6 +58,7 @@ enum AssemblySyntax { Intel, Gas, } + bitflags! { #[derive(Clone, Copy, Debug,PartialEq,Eq, Hash)] pub struct AvailableTransforms: u8 { @@ -154,8 +155,8 @@ impl Deoptimizer { pub fn set_transform_gadgets(&mut self, transforms: String) -> Result<(), DeoptimizerError> { let mut selected_transforms = AvailableTransforms::None; - let trs = transforms.split(","); - for (_i, t) in trs.enumerate() { + let trs = transforms.split(','); + for t in trs { match t.to_uppercase().as_str() { "AP" => selected_transforms |= AvailableTransforms::ArithmeticPartitioning, "LI" => selected_transforms |= AvailableTransforms::LogicalInverse, @@ -182,9 +183,7 @@ impl Deoptimizer { } pub fn set_skipped_offsets(&mut self, skipped: Vec<(u32, u32)>) { - if skipped.len() > 0 { - self.skipped_offsets = Some(skipped); - } + self.skipped_offsets = Some(skipped); } fn is_offset_skipped(&self, offset: u32) -> bool { @@ -234,7 +233,7 @@ impl Deoptimizer { let mut decoder = Decoder::with_ip(bitness, bytes, start_addr, DecoderOptions::NONE); let replaced_bytes: Vec; if self.skipped_offsets.is_some() { - replaced_bytes = self.replace_skipped_offsets(&bytes, 0x90)?; + replaced_bytes = self.replace_skipped_offsets(bytes, 0x90)?; decoder = Decoder::with_ip(bitness, &replaced_bytes, start_addr, DecoderOptions::NONE); } @@ -285,7 +284,7 @@ impl Deoptimizer { } for bt in branch_targets.iter() { - if !known_addr_table.contains(&bt) { + if !known_addr_table.contains(bt) { warn!( "Branch target 0x{:016X} is outside the known address sapce!", bt @@ -461,12 +460,7 @@ impl Deoptimizer { if acode.is_branch_target(inst.ip()) { ip_to_index_table.insert(inst.ip(), result.len()); } - match Deoptimizer::apply_transform( - acode.bitness, - &inst, - self.freq, - self.transforms.clone(), - ) { + match Deoptimizer::apply_transform(acode.bitness, &inst, self.freq, self.transforms) { Ok(dinst) => { result = [result, dinst.clone()].concat(); print_inst_diff(&inst, dinst); @@ -507,7 +501,7 @@ impl Deoptimizer { result[*idx] ); result[i] = set_branch_target( - &mut result[i].clone(), + &result[i].clone(), result[*idx].ip(), acode.bitness, )?; diff --git a/src/x86_64/helpers.rs b/src/x86_64/helpers.rs index 67ccae6..f93b511 100644 --- a/src/x86_64/helpers.rs +++ b/src/x86_64/helpers.rs @@ -20,7 +20,7 @@ pub fn random_immediate_value(kind: OpKind) -> Result { }) } -pub fn adjust_instruction_addrs(code: &mut Vec, start_addr: u64) { +pub fn adjust_instruction_addrs(code: &mut [Instruction], start_addr: u64) { let mut new_ip = start_addr; for inst in code.iter_mut() { inst.set_ip(new_ip); @@ -61,35 +61,35 @@ pub fn get_instruction_bytes(bitness: u32, insts: Vec) -> Result Option { - haystack - .windows(needle.len()) - .position(|window| window == needle) -} - -pub fn generate_random_instructions(size: usize) -> Vec { - let small_mnemonics = [ - 0x90, // nop - 0xc3, // ret - 0xf1, // int1 - 0xf4, // hlt - 0xf5, // cmc - 0xf8, // clc - 0xfa, // cli - 0xf9, // stc - 0xfb, // sti - 0xfc, // cld - ] - .to_vec(); - let mut output = Vec::new(); - for _ in 0..size { - output.push(*small_mnemonics.choose(&mut rand::thread_rng()).unwrap() as u8) - } - output -} +// pub fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option { +// haystack +// .windows(needle.len()) +// .position(|window| window == needle) +// } +// +// pub fn generate_random_instructions(size: usize) -> Vec { +// let small_mnemonics = [ +// 0x90, // nop +// 0xc3, // ret +// 0xf1, // int1 +// 0xf4, // hlt +// 0xf5, // cmc +// 0xf8, // clc +// 0xfa, // cli +// 0xf9, // stc +// 0xfb, // sti +// 0xfc, // cld +// ] +// .to_vec(); +// let mut output = Vec::new(); +// for _ in 0..size { +// output.push(*small_mnemonics.choose(&mut rand::thread_rng()).unwrap() as u8) +// } +// output +// } pub fn print_inst_diff(inst: &Instruction, dinst: Vec) { - if log::max_level() <= log::Level::Info || dinst.len() == 0 { + if log::max_level() <= log::Level::Info || dinst.is_empty() { return; } let inst_column_len = 48; @@ -119,18 +119,12 @@ pub fn print_inst_diff(inst: &Instruction, dinst: Vec) { } } else { println!( - "{:016X}:\t{}|\t{}", + "{:016X}:\t{}{}|\t{}{}", inst.ip(), - format!( - "{}{}", - inst_str.blue(), - " ".repeat(inst_column_len - inst_str.len()) - ), - format!( - "{}{}", - inst_str.blue(), - " ".repeat(inst_column_len - inst_str.len()) - ), + inst_str.blue(), + " ".repeat(inst_column_len - inst_str.len()), + inst_str.blue(), + " ".repeat(inst_column_len - inst_str.len()), ); } } @@ -189,18 +183,18 @@ pub fn transpose_fixed_register_operand(inst: &mut Instruction) -> Result<(), De // } // } -pub fn get_immediate_indexes(inst: &Instruction) -> Option> { - let mut indexes = Vec::new(); - for i in 0..inst.op_count() { - if is_immediate_operand(inst.op_kind(i)) { - indexes.push(i); - } - } - if indexes.len() == 0 { - return None; - } - Some(indexes) -} +// pub fn get_immediate_indexes(inst: &Instruction) -> Option> { +// let mut indexes = Vec::new(); +// for i in 0..inst.op_count() { +// if is_immediate_operand(inst.op_kind(i)) { +// indexes.push(i); +// } +// } +// if indexes.len() == 0 { +// return None; +// } +// Some(indexes) +// } pub fn get_stack_pointer_register(bitness: u32) -> Result { Ok(match bitness { @@ -234,25 +228,25 @@ pub fn to_db_mnemonic(bytes: &[u8]) -> String { db_inst.trim_end_matches(", ").to_string() } -pub fn get_register_save_seq( - bitness: u32, - reg: Register, -) -> Result<(Instruction, Instruction), DeoptimizerError> { - let mut full_reg = reg.full_register(); - if bitness != 64 { - full_reg = reg.full_register32(); - } - let (c1, c2) = match bitness { - 16 => (Code::Push_r16, Code::Pop_r16), - 32 => (Code::Push_r32, Code::Pop_r32), - 64 => (Code::Push_r64, Code::Pop_r64), - _ => return Err(DeoptimizerError::InvalidProcessorMode), - }; - Ok(( - Instruction::with1(c1, full_reg)?, - Instruction::with1(c2, full_reg)?, - )) -} +// pub fn get_register_save_seq( +// bitness: u32, +// reg: Register, +// ) -> Result<(Instruction, Instruction), DeoptimizerError> { +// let mut full_reg = reg.full_register(); +// if bitness != 64 { +// full_reg = reg.full_register32(); +// } +// let (c1, c2) = match bitness { +// 16 => (Code::Push_r16, Code::Pop_r16), +// 32 => (Code::Push_r32, Code::Pop_r32), +// 64 => (Code::Push_r64, Code::Pop_r64), +// _ => return Err(DeoptimizerError::InvalidProcessorMode), +// }; +// Ok(( +// Instruction::with1(c1, full_reg)?, +// Instruction::with1(c2, full_reg)?, +// )) +// } pub fn get_random_register_value(reg: Register) -> u64 { let mut rng = rand::thread_rng(); @@ -288,8 +282,7 @@ pub fn set_branch_target( bt: u64, bitness: u32, ) -> Result { - let mut my_inst = inst.clone(); - + let mut my_inst = *inst; if matches!(inst.op0_kind(), OpKind::FarBranch16 | OpKind::FarBranch32) { if bt < u16::MAX as u64 { my_inst.set_op0_kind(OpKind::FarBranch16); @@ -407,15 +400,15 @@ pub fn get_random_gp_register( let index = shuffed_regs.iter().position(|x| { x.full_register() == ex.register().full_register() || x == &ex.register() }); - if index.is_some() { - shuffed_regs.remove(index.unwrap()); + if let Some(idx) = index { + shuffed_regs.remove(idx); } } } for reg in shuffed_regs { let reg_str = format!("{:?}", reg); - let is_extended = reg_str.contains("R") || reg_str.contains("IL") || reg_str.contains("PL"); + let is_extended = reg_str.contains('R') || reg_str.contains("IL") || reg_str.contains("PL"); if is_extended == extended { return Ok(reg); } diff --git a/src/x86_64/tests.rs b/src/x86_64/tests.rs index 05bd238..911fc19 100644 --- a/src/x86_64/tests.rs +++ b/src/x86_64/tests.rs @@ -525,65 +525,65 @@ mod tests { println!("Legacy: {}", total - (vex + xop)); } - #[test] - fn temp() { - let code_64: &[u8] = &[ - 0x48, 0x8b, 0x00, 0x48, 0x8b, 0x40, 0x10, 0x48, 0x8b, 0x40, 0xf0, 0x48, 0x8d, 0x09, - 0x89, 0x38, 0x48, 0x8b, 0x4b, 0x28, 0x48, 0x89, 0x74, 0x24, 0x10, 0xc7, 0x45, 0x40, - 0x01, 0x00, 0x00, 0x00, 0x48, 0x89, 0x54, 0xc8, 0x28, 0x48, 0x8d, 0x0c, 0xc9, 0x41, - 0x0f, 0xb6, 0xb4, 0x80, 0x53, 0xb3, 0x0f, 0x00, 0x48, 0x81, 0x23, 0xff, 0x9f, 0xff, - 0xff, 0x48, 0x0f, 0xba, 0x2b, 0x0e, - ]; - let code_32: &[u8] = &[ - 0x68, 0xaa, 0x00, 0x00, 0x00, 0x68, 0xbb, 0xaa, 0x00, 0x00, 0x68, 0xdd, 0xcc, 0xbb, - 0xaa, 0x68, 0xff, 0xee, 0xdd, 0xcc, 0x68, 0xff, 0xff, 0x00, 0x00, 0x6a, 0xff, 0x6a, - 0xff, - ]; - let mut decoder64 = Decoder::new(64, code_32, DecoderOptions::NONE); - let mut decoder32 = Decoder::new(32, code_32, DecoderOptions::NONE); - let mut inst = Instruction::default(); - let mut offset = 0; - - fn convert_to_byte_value_instructions( - bitness: u32, - bytes: &[u8], - rip: u64, - ) -> Result, DeoptimizerError> { - let mut result = Vec::new(); - // let bytes = get_instruction_bytes(bitness, [inst].to_vec())?; - for b in bytes.iter() { - result.push(Instruction::with_declare_byte_1(*b)); - } - Ok(rencode(bitness, result, rip)?) - } - - while decoder64.can_decode() { - decoder64.decode_out(&mut inst); - let mut dbs = convert_to_byte_value_instructions( - 64, - &code_64[offset as usize..offset as usize + inst.len()], - inst.ip(), - ) - .expect("db convertion failed"); - // let disp_size = inst.memory_displ_size(); - // let mem_disp = inst.memory_displacement64(); - for i in dbs.iter_mut() { - println!("[i] {} -> {:?} - ({:?})", i, i.code(), i.mnemonic()); - i.set_code(Code::DeclareByte); - println!(">> {} -> {:?} - {:?}", i, i.code(), i.mnemonic()); - } - - offset += inst.len(); - // println!("\t--> op1_kind: {:?}", inst.op0_kind()); - // println!("\t--> mem_disp: {}", mem_disp); - // println!("\t--> mem_disp_size: {}", disp_size); - // println!( - // "\t--> mem_disp_sign: {}", - // mem_disp < u64::pow(2, disp_size * 8) / 2 - // ); - } - - println!("i32 MIN: {}", i32::MIN); - println!("i32 MAX: {}", i32::MAX); - } + // #[test] + // fn temp() { + // let code_64: &[u8] = &[ + // 0x48, 0x8b, 0x00, 0x48, 0x8b, 0x40, 0x10, 0x48, 0x8b, 0x40, 0xf0, 0x48, 0x8d, 0x09, + // 0x89, 0x38, 0x48, 0x8b, 0x4b, 0x28, 0x48, 0x89, 0x74, 0x24, 0x10, 0xc7, 0x45, 0x40, + // 0x01, 0x00, 0x00, 0x00, 0x48, 0x89, 0x54, 0xc8, 0x28, 0x48, 0x8d, 0x0c, 0xc9, 0x41, + // 0x0f, 0xb6, 0xb4, 0x80, 0x53, 0xb3, 0x0f, 0x00, 0x48, 0x81, 0x23, 0xff, 0x9f, 0xff, + // 0xff, 0x48, 0x0f, 0xba, 0x2b, 0x0e, + // ]; + // let code_32: &[u8] = &[ + // 0x68, 0xaa, 0x00, 0x00, 0x00, 0x68, 0xbb, 0xaa, 0x00, 0x00, 0x68, 0xdd, 0xcc, 0xbb, + // 0xaa, 0x68, 0xff, 0xee, 0xdd, 0xcc, 0x68, 0xff, 0xff, 0x00, 0x00, 0x6a, 0xff, 0x6a, + // 0xff, + // ]; + // let mut decoder64 = Decoder::new(64, code_32, DecoderOptions::NONE); + // let decoder32 = Decoder::new(32, code_32, DecoderOptions::NONE); + // let mut inst = Instruction::default(); + // let mut offset = 0; + // + // fn convert_to_byte_value_instructions( + // bitness: u32, + // bytes: &[u8], + // rip: u64, + // ) -> Result, DeoptimizerError> { + // let mut result = Vec::new(); + // // let bytes = get_instruction_bytes(bitness, [inst].to_vec())?; + // for b in bytes.iter() { + // result.push(Instruction::with_declare_byte_1(*b)); + // } + // Ok(rencode(bitness, result, rip)?) + // } + // + // while decoder64.can_decode() { + // decoder64.decode_out(&mut inst); + // let mut dbs = convert_to_byte_value_instructions( + // 64, + // &code_64[offset as usize..offset as usize + inst.len()], + // inst.ip(), + // ) + // .expect("db convertion failed"); + // // let disp_size = inst.memory_displ_size(); + // // let mem_disp = inst.memory_displacement64(); + // for i in dbs.iter_mut() { + // println!("[i] {} -> {:?} - ({:?})", i, i.code(), i.mnemonic()); + // i.set_code(Code::DeclareByte); + // println!(">> {} -> {:?} - {:?}", i, i.code(), i.mnemonic()); + // } + // + // offset += inst.len(); + // // println!("\t--> op1_kind: {:?}", inst.op0_kind()); + // // println!("\t--> mem_disp: {}", mem_disp); + // // println!("\t--> mem_disp_size: {}", disp_size); + // // println!( + // // "\t--> mem_disp_sign: {}", + // // mem_disp < u64::pow(2, disp_size * 8) / 2 + // // ); + // } + // + // println!("i32 MIN: {}", i32::MIN); + // println!("i32 MAX: {}", i32::MAX); + // } } diff --git a/src/x86_64/transforms/arithmetic_partitioning.rs b/src/x86_64/transforms/arithmetic_partitioning.rs index b9751dc..0c220cc 100644 --- a/src/x86_64/transforms/arithmetic_partitioning.rs +++ b/src/x86_64/transforms/arithmetic_partitioning.rs @@ -18,7 +18,7 @@ pub fn apply_ap_transform( }; let rand_imm_val = random_immediate_value(kind)?; let imm_delta: u64 = rand_imm_val.abs_diff(imm); - let mut fix_inst = inst.clone(); + let mut fix_inst = *inst; if inst.mnemonic() == Mnemonic::Push { let sp_reg = get_stack_pointer_register(bitness)?; let op0_size = get_op_size(0, inst)? * 8; @@ -30,7 +30,7 @@ pub fn apply_ap_transform( } if inst.mnemonic() == Mnemonic::Pop { let mut info_factory = InstructionInfoFactory::new(); - let info = info_factory.info(&inst); + let info = info_factory.info(inst); let op0_size = get_op_size(0, inst)? * 8; let rand_reg = get_random_gp_register(bitness == 64, op0_size, Some(info.used_registers()))?; diff --git a/src/x86_64/transforms/condition_expand.rs b/src/x86_64/transforms/condition_expand.rs index 87bb30d..28e5e80 100644 --- a/src/x86_64/transforms/condition_expand.rs +++ b/src/x86_64/transforms/condition_expand.rs @@ -24,9 +24,9 @@ pub fn apply_ce_transform( if inst.is_loopcc() || inst.is_loop() { let mut dec = match bitness { - 16 => Instruction::with2(Code::Dec_r16, Register::CX, Register::CX)?, - 32 => Instruction::with2(Code::Dec_r32, Register::ECX, Register::ECX)?, - 64 => Instruction::with2(Code::Dec_rm64, Register::RCX, Register::RCX)?, + 16 => Instruction::with1(Code::Dec_r16, Register::CX)?, + 32 => Instruction::with1(Code::Dec_r32, Register::ECX)?, + 64 => Instruction::with1(Code::Dec_rm64, Register::RCX)?, _ => return Err(DeoptimizerError::InvalidProcessorMode), }; dec = *rencode(bitness, [dec].to_vec(), inst.ip())? @@ -36,7 +36,7 @@ pub fn apply_ce_transform( Mnemonic::Loop | Mnemonic::Loope => { asm.jnz(bt)?; let insts = asm.instructions(); - let mut jnz = insts.first().unwrap().clone(); + let mut jnz = *insts.first().unwrap(); jnz.set_ip(dec.next_ip()); jnz.as_near_branch(); if inst.mnemonic() == Mnemonic::Loope { @@ -48,7 +48,7 @@ pub fn apply_ce_transform( Mnemonic::Loopne => { asm.jz(bt)?; let insts = asm.instructions(); - let mut jz = insts.first().unwrap().clone(); + let mut jz = *insts.first().unwrap(); jz.set_ip(dec.next_ip()); jz.as_near_branch(); return Ok(rencode(bitness, [dec, jz].to_vec(), inst.ip())?); @@ -63,7 +63,7 @@ pub fn apply_ce_transform( ) { asm.jz(bt)?; let insts = asm.instructions(); - let mut jz = insts.first().unwrap().clone(); + let mut jz = *insts.first().unwrap(); jz.set_ip(test.next_ip()); jz.as_near_branch(); return Ok(rencode(bitness, [test, jz].to_vec(), inst.ip())?); diff --git a/src/x86_64/transforms/immediate_to_register.rs b/src/x86_64/transforms/immediate_to_register.rs index 6bacb05..1f290d8 100644 --- a/src/x86_64/transforms/immediate_to_register.rs +++ b/src/x86_64/transforms/immediate_to_register.rs @@ -1,103 +1,103 @@ -use crate::x86_64::apply_ap_transform; -use crate::x86_64::helpers::*; -use crate::x86_64::DeoptimizerError; -use iced_x86::*; +// use crate::x86_64::apply_ap_transform; +// use crate::x86_64::helpers::*; +// use crate::x86_64::DeoptimizerError; +// use iced_x86::*; -/// Applies immidiate-to-register transform to given instruction. -pub fn apply_itr_transform( - bitness: u32, - inst: &mut Instruction, -) -> Result, DeoptimizerError> { - if inst.is_stack_instruction() || !is_itr_compatible(inst) || is_using_fixed_register(inst) { - return Err(DeoptimizerError::TransformNotPossible); - } - let idxs = match get_immediate_indexes(inst) { - Some(i) => i, - None => return Err(DeoptimizerError::TransformNotPossible), - }; - transpose_fixed_register_operand(inst)?; - let rip = inst.ip(); - let mut info_factory = InstructionInfoFactory::new(); - let info = info_factory.info(&inst); - let imm_index = *idxs.first().unwrap(); - let imm = inst.immediate(imm_index); - let imm_size = get_op_size(imm_index, inst)?; - let rand_reg = get_random_gp_register( - bitness == 64, - imm_size as usize, - Some(info.used_registers()), - )?; - let (reg_save_pre, reg_save_post) = get_register_save_seq(bitness, rand_reg)?; - let mov_op_size = imm_size * 8; - let mut mov_code = get_code_with_str(&format!("Mov_rm{mov_op_size}_imm{mov_op_size}")); - let mut new_code = get_code_with_str(&format!("{:?}", inst.code()).replace("imm", "rm")); - if new_code == Code::INVALID { - new_code = get_code_with_str(&format!("{:?}", inst.code()).replace("imm", "r")); - } - inst.set_op_kind(*idxs.first().unwrap(), OpKind::Register); - println!("code: {:?}", inst.code()); - let mut mov: Instruction; - if imm > u64::pow(2, mov_op_size as u32) { - mov_code = get_code_with_str(&format!("Mov_rm{}_imm{}", mov_op_size * 2, mov_op_size * 2)); - // This is for fixing sign extended instructions... - if mov_op_size * 2 == 64 { - // This means it is a sign extended immediate operand - mov_code = get_code_with_str(&format!("Mov_r64_imm64")); - } - println!("op0: {mov_op_size} | op1: {mov_op_size}"); - println!("mov_code: {:?}", mov_code); - if new_code == Code::INVALID { - new_code = get_code_with_str(&format!("{:?}", inst.code()).replace( - &format!("imm{mov_op_size}"), - &format!("r{}", mov_op_size * 2), - )); - } - if new_code == Code::INVALID { - new_code = get_code_with_str(&format!("{:?}", inst.code()).replace( - &format!("imm{mov_op_size}"), - &format!("rm{}", mov_op_size * 2), - )); - } - mov = Instruction::with2(mov_code, rand_reg.full_register(), imm)?; - inst.set_op_register(*idxs.first().unwrap(), rand_reg.full_register()); - } else { - println!("mov_code: {:?}", mov_code); - mov = Instruction::with2(mov_code, rand_reg, imm)?; - inst.set_op_register(*idxs.first().unwrap(), rand_reg); - } - - println!("new_code: {:?}", new_code); - // Obfuscate mov... - let obs_mov = apply_ap_transform(bitness, &mut mov)?; - - inst.set_code(new_code); - let mut result = [[reg_save_pre].to_vec(), obs_mov].concat(); - result.push(*inst); - result.push(reg_save_post); - Ok(rencode(bitness, result, rip)?) -} - -pub fn is_itr_compatible(inst: &Instruction) -> bool { - let mut my_inst = inst.clone(); - let idx = match get_immediate_indexes(inst) { - Some(i) => i, - None => return false, - }; - - let imm_size = match get_op_size(*idx.first().unwrap(), inst) { - Ok(i) => i * 8, - Err(_) => return false, - }; - - let _ = transpose_fixed_register_operand(&mut my_inst); // we can ignore the error - get_code_with_str(&format!("{:?}", my_inst.code()).replace("imm", "rm")) != Code::INVALID - || get_code_with_str(&format!("{:?}", my_inst.code()).replace("imm", "r")) != Code::INVALID - || get_code_with_str( - &format!("{:?}", my_inst.code()) - .replace(&format!("imm{imm_size}"), &format!("r{}", imm_size * 2)), - ) != Code::INVALID - || get_code_with_str( - &format!("{:?}", my_inst.code()) - .replace(&format!("imm{imm_size}"), &format!("rm{}", imm_size * 2)), - ) != Code::INVALID -} +// /// Applies immidiate-to-register transform to given instruction. +// pub fn apply_itr_transform( +// bitness: u32, +// inst: &mut Instruction, +// ) -> Result, DeoptimizerError> { +// if inst.is_stack_instruction() || !is_itr_compatible(inst) || is_using_fixed_register(inst) { +// return Err(DeoptimizerError::TransformNotPossible); +// } +// let idxs = match get_immediate_indexes(inst) { +// Some(i) => i, +// None => return Err(DeoptimizerError::TransformNotPossible), +// }; +// transpose_fixed_register_operand(inst)?; +// let rip = inst.ip(); +// let mut info_factory = InstructionInfoFactory::new(); +// let info = info_factory.info(&inst); +// let imm_index = *idxs.first().unwrap(); +// let imm = inst.immediate(imm_index); +// let imm_size = get_op_size(imm_index, inst)?; +// let rand_reg = get_random_gp_register( +// bitness == 64, +// imm_size as usize, +// Some(info.used_registers()), +// )?; +// let (reg_save_pre, reg_save_post) = get_register_save_seq(bitness, rand_reg)?; +// let mov_op_size = imm_size * 8; +// let mut mov_code = get_code_with_str(&format!("Mov_rm{mov_op_size}_imm{mov_op_size}")); +// let mut new_code = get_code_with_str(&format!("{:?}", inst.code()).replace("imm", "rm")); +// if new_code == Code::INVALID { +// new_code = get_code_with_str(&format!("{:?}", inst.code()).replace("imm", "r")); +// } +// inst.set_op_kind(*idxs.first().unwrap(), OpKind::Register); +// println!("code: {:?}", inst.code()); +// let mut mov: Instruction; +// if imm > u64::pow(2, mov_op_size as u32) { +// mov_code = get_code_with_str(&format!("Mov_rm{}_imm{}", mov_op_size * 2, mov_op_size * 2)); +// // This is for fixing sign extended instructions... +// if mov_op_size * 2 == 64 { +// // This means it is a sign extended immediate operand +// mov_code = get_code_with_str(&format!("Mov_r64_imm64")); +// } +// println!("op0: {mov_op_size} | op1: {mov_op_size}"); +// println!("mov_code: {:?}", mov_code); +// if new_code == Code::INVALID { +// new_code = get_code_with_str(&format!("{:?}", inst.code()).replace( +// &format!("imm{mov_op_size}"), +// &format!("r{}", mov_op_size * 2), +// )); +// } +// if new_code == Code::INVALID { +// new_code = get_code_with_str(&format!("{:?}", inst.code()).replace( +// &format!("imm{mov_op_size}"), +// &format!("rm{}", mov_op_size * 2), +// )); +// } +// mov = Instruction::with2(mov_code, rand_reg.full_register(), imm)?; +// inst.set_op_register(*idxs.first().unwrap(), rand_reg.full_register()); +// } else { +// println!("mov_code: {:?}", mov_code); +// mov = Instruction::with2(mov_code, rand_reg, imm)?; +// inst.set_op_register(*idxs.first().unwrap(), rand_reg); +// } +// +// println!("new_code: {:?}", new_code); +// // Obfuscate mov... +// let obs_mov = apply_ap_transform(bitness, &mut mov)?; +// +// inst.set_code(new_code); +// let mut result = [[reg_save_pre].to_vec(), obs_mov].concat(); +// result.push(*inst); +// result.push(reg_save_post); +// Ok(rencode(bitness, result, rip)?) +// } +// +// pub fn is_itr_compatible(inst: &Instruction) -> bool { +// let mut my_inst = inst.clone(); +// let idx = match get_immediate_indexes(inst) { +// Some(i) => i, +// None => return false, +// }; +// +// let imm_size = match get_op_size(*idx.first().unwrap(), inst) { +// Ok(i) => i * 8, +// Err(_) => return false, +// }; +// +// let _ = transpose_fixed_register_operand(&mut my_inst); // we can ignore the error +// get_code_with_str(&format!("{:?}", my_inst.code()).replace("imm", "rm")) != Code::INVALID +// || get_code_with_str(&format!("{:?}", my_inst.code()).replace("imm", "r")) != Code::INVALID +// || get_code_with_str( +// &format!("{:?}", my_inst.code()) +// .replace(&format!("imm{imm_size}"), &format!("r{}", imm_size * 2)), +// ) != Code::INVALID +// || get_code_with_str( +// &format!("{:?}", my_inst.code()) +// .replace(&format!("imm{imm_size}"), &format!("rm{}", imm_size * 2)), +// ) != Code::INVALID +// } diff --git a/src/x86_64/transforms/logical_inverse.rs b/src/x86_64/transforms/logical_inverse.rs index f04cf46..224b21c 100644 --- a/src/x86_64/transforms/logical_inverse.rs +++ b/src/x86_64/transforms/logical_inverse.rs @@ -24,25 +24,25 @@ pub fn apply_li_transform( let result = match mnemonic { Mnemonic::Xor => { set_op_immediate(inst, 1, !imm)?; - let mut not = inst.clone(); + let mut not = *inst; not.set_code(get_code_with_str(&format!("Not_rm{op0_size}"))); [not, *inst].to_vec() } Mnemonic::And => { - let mut or = inst.clone(); + let mut or = *inst; or.set_code(get_code_with_str(&format!("Or_rm{op0_size}_imm{op1_size}"))); set_op_immediate(&mut or, 1, !imm)?; - let mut not = inst.clone(); + let mut not = *inst; not.set_code(get_code_with_str(&format!("Not_rm{op0_size}"))); [not, or, not].to_vec() } Mnemonic::Or => { - let mut and = inst.clone(); + let mut and = *inst; and.set_code(get_code_with_str(&format!( "And_rm{op0_size}_imm{op1_size}" ))); set_op_immediate(&mut and, 1, !imm)?; - let mut not = inst.clone(); + let mut not = *inst; not.set_code(get_code_with_str(&format!("Not_rm{op0_size}"))); [not, and, not].to_vec() } diff --git a/src/x86_64/transforms/logical_partitioning.rs b/src/x86_64/transforms/logical_partitioning.rs index 35c7462..4e54ed3 100644 --- a/src/x86_64/transforms/logical_partitioning.rs +++ b/src/x86_64/transforms/logical_partitioning.rs @@ -26,7 +26,7 @@ pub fn apply_lp_transform( // This is simple x2 or /2 match mnemonic { Mnemonic::Shr | Mnemonic::Sar => { - let mut and = inst.clone(); + let mut and = *inst; let mut op1_size = op0_size * 8; if op1_size == 64 { op1_size = 32; @@ -90,20 +90,18 @@ pub fn apply_lp_transform( } _ => return Err(DeoptimizerError::TransformNotPossible), } + } else if imm.is_power_of_two() { + let mut shift1 = *inst; + let mut shift2 = *inst; + shift1.set_immediate8(imm as u8 / 2); + shift2.set_immediate8(imm as u8 / 2); + [shift1, shift2].to_vec() } else { - if imm.is_power_of_two() { - let mut shift1 = inst.clone(); - let mut shift2 = inst.clone(); - shift1.set_immediate8(imm as u8 / 2); - shift2.set_immediate8(imm as u8 / 2); - [shift1, shift2].to_vec() - } else { - let mut shift1 = inst.clone(); - let mut shift2 = inst.clone(); - shift1.set_immediate8(((imm - 1) as u8 / 2) + 1); - shift2.set_immediate8((imm - 1) as u8 / 2); - [shift1, shift2].to_vec() - } + let mut shift1 = *inst; + let mut shift2 = *inst; + shift1.set_immediate8(((imm - 1) as u8 / 2) + 1); + shift2.set_immediate8((imm - 1) as u8 / 2); + [shift1, shift2].to_vec() } } Mnemonic::Ror | Mnemonic::Rcr | Mnemonic::Rol | Mnemonic::Rcl => { @@ -112,7 +110,7 @@ pub fn apply_lp_transform( OpKind::Register => (inst.op0_register().size() * 8) as u64, _ => return Err(DeoptimizerError::InvalidTemplate), }; - imm = imm % dst_op_size; + imm %= dst_op_size; let pow = rand::thread_rng().gen_range(2..(u8::MAX as u64 / dst_op_size) as u8); inst.set_immediate8((dst_op_size * pow as u64 + imm) as u8); [*inst].to_vec() diff --git a/src/x86_64/transforms/mod.rs b/src/x86_64/transforms/mod.rs index 2ffe2c5..b49421a 100644 --- a/src/x86_64/transforms/mod.rs +++ b/src/x86_64/transforms/mod.rs @@ -7,7 +7,7 @@ mod offset_mutation; mod register_swap; pub use arithmetic_partitioning::*; pub use condition_expand::*; -pub use immediate_to_register::*; +// pub use immediate_to_register::*; pub use logical_inverse::*; pub use logical_partitioning::*; pub use offset_mutation::*; diff --git a/src/x86_64/transforms/offset_mutation.rs b/src/x86_64/transforms/offset_mutation.rs index bf11262..17f361d 100644 --- a/src/x86_64/transforms/offset_mutation.rs +++ b/src/x86_64/transforms/offset_mutation.rs @@ -1,3 +1,5 @@ +use std::u64; + use crate::x86_64::helpers::*; use crate::x86_64::DeoptimizerError; use iced_x86::*; @@ -26,7 +28,7 @@ pub fn apply_om_transform( let old_mem_disp_sign = mem_disp as i32 > 0; // The sign of the memory displacement let abs_old_mem_disp = match old_mem_disp_sign { true => mem_disp, - false => (mem_disp as i32).abs() as u64, + false => (mem_disp as i32).unsigned_abs() as u64, }; let (c1, c2) = match new_mem_disp_sign { true => ( @@ -42,14 +44,14 @@ pub fn apply_om_transform( let fix_val = match (new_mem_disp_sign, old_mem_disp_sign) { (true, true) => mem_disp.abs_diff(rand_val), (false, false) => match base_reg.size() { - 1 => ((rand_val as i8).abs() as u64).abs_diff(abs_old_mem_disp), - 2 => ((rand_val as i16).abs() as u64).abs_diff(abs_old_mem_disp), - _ => ((rand_val as i32).abs() as u64).abs_diff(abs_old_mem_disp), + 1 => ((rand_val as i8).unsigned_abs() as u64).abs_diff(abs_old_mem_disp), + 2 => ((rand_val as i16).unsigned_abs() as u64).abs_diff(abs_old_mem_disp), + _ => ((rand_val as i32).unsigned_abs() as u64).abs_diff(abs_old_mem_disp), }, (true, false) | (false, true) => match base_reg.size() { - 1 => ((rand_val as i8).abs() as u64) + abs_old_mem_disp, - 2 => ((rand_val as i16).abs() as u64) + abs_old_mem_disp, - _ => ((rand_val as i32).abs() as u64) + abs_old_mem_disp, + 1 => ((rand_val as i8).unsigned_abs() as u64) + abs_old_mem_disp, + 2 => ((rand_val as i16).unsigned_abs() as u64) + abs_old_mem_disp, + _ => ((rand_val as i32).unsigned_abs() as u64) + abs_old_mem_disp, }, }; @@ -60,7 +62,7 @@ pub fn apply_om_transform( inst.set_memory_displ_size(bitness / 8); inst.set_memory_displacement64(rand_val); - let mut result = [pre_inst, inst.clone()].to_vec(); + let mut result = [pre_inst, *inst].to_vec(); if base_reg.full_register() != inst.op0_register().full_register() { result.push(post_inst); } @@ -71,7 +73,7 @@ pub fn apply_om_transform( pub fn is_om_compatible(inst: &Instruction) -> bool { let base_reg = inst.memory_base(); let mut info_factory = InstructionInfoFactory::new(); - let info = info_factory.info(&inst); + let info = info_factory.info(inst); if !matches!( inst.mnemonic(), Mnemonic::Mov | Mnemonic::Movzx | Mnemonic::Movd | Mnemonic::Movq | Mnemonic::Lea diff --git a/src/x86_64/transforms/register_swap.rs b/src/x86_64/transforms/register_swap.rs index 820897a..8b8a446 100644 --- a/src/x86_64/transforms/register_swap.rs +++ b/src/x86_64/transforms/register_swap.rs @@ -15,7 +15,7 @@ pub fn apply_rs_transform( transpose_fixed_register_operand(inst)?; let rip = inst.ip(); let mut info_factory = InstructionInfoFactory::new(); - let info = info_factory.info(&inst); + let info = info_factory.info(inst); let mut used_regs = Vec::new(); for i in 0..inst.op_count() { if inst.op_kind(i) != OpKind::Register { @@ -26,7 +26,7 @@ pub fn apply_rs_transform( } } - if used_regs.len() == 0 { + if used_regs.is_empty() { return Err(DeoptimizerError::TransformNotPossible); } let swap_reg = *used_regs.choose(&mut rand::thread_rng()).unwrap(); @@ -45,12 +45,12 @@ pub fn apply_rs_transform( swap_reg.size() * 8 )); let xchg = Instruction::with2(xchg_code, swap_reg, rand_reg)?; - Ok(rencode(bitness, [xchg, inst.clone(), xchg].to_vec(), rip)?) + Ok(rencode(bitness, [xchg, *inst, xchg].to_vec(), rip)?) } pub fn is_rs_compatible(inst: &Instruction) -> bool { let mut info_factory = InstructionInfoFactory::new(); - let info = info_factory.info(&inst); + let info = info_factory.info(inst); for r in info.used_registers() { if r.register().full_register() == Register::RSP { return false;