├── vgk.tar.gz ├── Cargo.toml ├── optimize_llvm.sh ├── src ├── symbolic.rs ├── util.rs ├── main.rs ├── transforms.rs ├── match_assembly.rs ├── vm_handler.rs └── vm_matchers.rs ├── README.md └── Cargo.lock /vgk.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmh5225/VMP-Vmp3_64bit_disasm-prerelease-/HEAD/vgk.tar.gz -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vmp3_disasm" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | iced-x86 = "*" 10 | clap = {version = "*", features = ["derive"]} 11 | pelite = "*" 12 | haybale = { version = "*", features = ["llvm-13", "vendor-boolector"] } 13 | inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm13-0"] } 14 | petgraph = "*" 15 | -------------------------------------------------------------------------------- /optimize_llvm.sh: -------------------------------------------------------------------------------- 1 | for i in {1..2} 2 | do 3 | opt devirt.ll --always-inline --cfl-steens-aa --cfl-anders-aa --tbaa --scoped-noalias-aa --simplifycfg --sroa --early-cse-memssa --instcombine --simplifycfg --gvn-hoist --gvn-sink --dse --instcombine --simplifycfg -S -o devirt.ll 4 | done 5 | 6 | # @RAM = external dso_local local_unnamed_addr global [0 x i8], align 1 7 | # @RAM = dso_local constant [0 x i8] zeroinitializer, align 1 8 | sed -i "s/RAM = external dso_local local_unnamed_addr global \[0 x i8\], align 1/RAM = dso_local constant [0 x i8] zeroinitializer, align 1/" devirt.ll 9 | sed -i "s/local_unnamed_addr global i64 undef, align 8/constant i64 undef, align 8/" devirt.ll 10 | 11 | for i in {1..2} 12 | do 13 | opt devirt.ll --always-inline --cfl-steens-aa --cfl-anders-aa --tbaa --scoped-noalias-aa --simplifycfg --sroa --early-cse-memssa --instcombine --simplifycfg --gvn-hoist --gvn-sink --dse --instcombine --simplifycfg -S -o devirt.ll 14 | done 15 | 16 | #llvm-as devirt.ll 17 | # 18 | #clang devirt.ll -c -O0 19 | #binaryninja devirt.o 20 | -------------------------------------------------------------------------------- /src/symbolic.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | use haybale::{ 4 | config::NullPointerChecking, get_possible_return_values_of_func, Config, Project, ReturnValue, 5 | }; 6 | 7 | pub fn get_possible_solutions(function_name: &str) -> Result, Box> { 8 | let project = Project::from_bc_path("devirt.bc")?; 9 | 10 | // println!("Pointer size = {}", project.pointer_size_bits()); 11 | 12 | let mut config: Config = Default::default(); 13 | config.loop_bound = 1000; 14 | config.null_pointer_checking = NullPointerChecking::None; 15 | 16 | config.function_hooks.add("llvm.ctpop.i8", &|state, call| { 17 | let _arguments = call.get_arguments(); 18 | Ok(ReturnValue::Return(state.new_bv_with_name("ctpop".into(), 19 | 8) 20 | .unwrap())) 21 | }); 22 | config.function_hooks.add("llvm.fshl.i64", &|state, call| { 23 | let _arguments = call.get_arguments(); 24 | Ok(ReturnValue::Return(state.new_bv_with_name("fshl".into(), 25 | 64) 26 | .unwrap())) 27 | }); 28 | config.function_hooks.add("llvm.fshl.i32", &|state, call| { 29 | let _arguments = call.get_arguments(); 30 | Ok(ReturnValue::Return(state.new_bv_with_name("fshl".into(), 31 | 32) 32 | .unwrap())) 33 | }); 34 | config.function_hooks.add("llvm.x86.rdtsc", &|state, call| { 35 | let _arguments = call.get_arguments(); 36 | Ok(ReturnValue::Return(state.new_bv_with_name("rdtsc".into(), 37 | 64) 38 | .unwrap())) 39 | }); 40 | config.function_hooks.add_inline_asm_hook(&|state, call| { 41 | let _arguments = call.get_arguments(); 42 | Ok(ReturnValue::Return(state.new_bv_with_name("cr0".into(), 43 | 64) 44 | .unwrap())) 45 | }); 46 | config.function_hooks 47 | .add_default_hook(&|_, _| Ok(ReturnValue::ReturnVoid)); 48 | 49 | let possible_solutions = 50 | get_possible_return_values_of_func(function_name, &project, config, None, None, 10); 51 | 52 | let mut solutions_return = Vec::new(); 53 | match possible_solutions { 54 | haybale::solver_utils::PossibleSolutions::Exactly(solutions) => { 55 | for solution in solutions { 56 | match solution { 57 | ReturnValue::Return(value) => { 58 | // println!("Branch target -> {:x}", value); 59 | solutions_return.push(value); 60 | }, 61 | ReturnValue::ReturnVoid => panic!(), 62 | ReturnValue::Throw(_) => panic!(), 63 | ReturnValue::Abort => panic!(), 64 | }; 65 | } 66 | }, 67 | haybale::solver_utils::PossibleSolutions::AtLeast(_) => { 68 | panic!("More than 10 options for next vip!") 69 | }, 70 | } 71 | Ok(solutions_return) 72 | } 73 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::{ 2 | Code, Decoder, DecoderOptions, Instruction, InstructionInfoFactory, InstructionInfoOptions, 3 | OpAccess, Register, 4 | }; 5 | use pelite::pe64::{Pe, PeFile}; 6 | 7 | /// Read bytes at virtual address 8 | pub fn read_bytes_at_va<'a>(pe_file: &'_ PeFile, 9 | pe_bytes: &'a [u8], 10 | va: u64, 11 | size: usize) 12 | -> Result<&'a [u8], pelite::Error> { 13 | // Relative virtual address 14 | let rva = pe_file.va_to_rva(va)?; 15 | let file_offset = pe_file.rva_to_file_offset(rva)?; 16 | 17 | let bytes = &pe_bytes[file_offset .. file_offset + size]; 18 | Ok(bytes) 19 | } 20 | 21 | /// Disassemble instruction at virtual address 22 | pub fn disassemble_instruction_at_va(pe_file: &PeFile, 23 | pe_bytes: &[u8], 24 | instruction_address: u64) 25 | -> Instruction { 26 | let instruction_bytes = read_bytes_at_va(pe_file, pe_bytes, instruction_address, 16).unwrap(); 27 | 28 | // Decode the instruction 29 | let mut decoder = Decoder::with_ip(64, 30 | instruction_bytes, 31 | instruction_address, 32 | DecoderOptions::NONE); 33 | 34 | decoder.decode() 35 | } 36 | 37 | /// Handle the calls into vm stub that looks like: 38 | /// push_call_addr -> push imm 39 | /// call vm_entry 40 | pub fn handle_vm_call(pe_file: &PeFile, 41 | pe_bytes: &[u8], 42 | push_call_addr: u64) 43 | -> (u64, u64) { 44 | let push_instruction = disassemble_instruction_at_va(pe_file, pe_bytes, push_call_addr); 45 | let call_instruction = disassemble_instruction_at_va(pe_file, 46 | pe_bytes, 47 | push_call_addr + 48 | push_instruction.len() as u64); 49 | 50 | // Check if the instructions match the expected opcodes 51 | if push_instruction.code() != Code::Pushq_imm32 { 52 | panic!("Vm Entry address is not correctly chosen"); 53 | } 54 | 55 | if call_instruction.code() != Code::Call_rel32_64 { 56 | panic!("Vm Entry address is not correctly chosen"); 57 | } 58 | 59 | let pushed_val = push_instruction.immediate32to64() as u64; 60 | let vm_entry_address = call_instruction.near_branch64(); 61 | 62 | (pushed_val, vm_entry_address) 63 | } 64 | 65 | /// Check wether a given register is written by the given instruction 66 | pub fn check_full_reg_written(instruction: &Instruction, 67 | reg: Register) 68 | -> bool { 69 | // Create an instruction factory to get more information about the instruction 70 | let mut instruction_info_factory = InstructionInfoFactory::new(); 71 | 72 | // Get the instruction info from the factory 73 | let instruction_info = 74 | instruction_info_factory.info_options(instruction, InstructionInfoOptions::NO_MEMORY_USAGE); 75 | 76 | let used_registers = instruction_info.used_registers(); 77 | 78 | for used_register in 79 | used_registers.iter() 80 | .filter(|r| r.register().full_register() == reg.full_register()) 81 | { 82 | // Check if any type of write happens 83 | match used_register.access() { 84 | OpAccess::Write | 85 | OpAccess::CondWrite | 86 | OpAccess::ReadWrite | 87 | OpAccess::ReadCondWrite => { 88 | return true; 89 | }, 90 | _ => { 91 | continue; 92 | }, 93 | } 94 | } 95 | 96 | false 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vmp3_64bit_disasm-prerelease- WIP WIP WIP 2 | Not all handlers supported yet! 3 | Basic branching supported! 4 | Currently working on loops and branches with more than 2 targets 5 | Comming soon ! 6 | ## Info 7 | 8 | This project was tested on vgk.sys (sha-1 266ddd98fdd9df939993d947b0edb052a347316f) 9 | 10 | ## Example 11 | 12 | ### Call into vmp3 with pushed value 13 | ![example1](https://user-images.githubusercontent.com/102005914/175548145-8cb85a51-fef4-4a4c-b11b-f8049636b590.png) 14 | 15 | ### Converting the address to decimal ( Newest commit fixed this use hex addresses now ) 16 | ![example2](https://user-images.githubusercontent.com/102005914/175548162-5d352eda-c66c-481b-ac7a-1697faa23e09.png) 17 | 18 | ### Invoking the disassembler 19 | ![example3](https://user-images.githubusercontent.com/102005914/175548166-ccc3bde9-fd20-44b7-850e-5b2c07119874.png) 20 | 21 | ## Example Output 22 | ``` 23 | 0x14039cf4b | pop64 r19 | 0x140725d72 24 | 0x14039cf50 | pop64 r10 | 0x14069504f 25 | 0x14039cf55 | pop64 r9 | 0x1406d0453 26 | 0x14039cf5a | pop64 r18 | 0x14069a8da 27 | 0x14039cf5f | pop64 r11 | 0x1406de987 28 | 0x14039cf64 | pop64 r22 | 0x140740966 29 | 0x14039cf69 | pop64 r21 | 0x14076a534 30 | 0x14039cf6e | pop64 r8 | 0x14073cc29 31 | 0x14039cf73 | pop64 r17 | 0x14066b565 32 | 0x14039cf78 | pop64 r7 | 0x1406c5fd7 33 | 0x14039cf7d | pop64 r5 | 0x1406a0a37 34 | 0x14039cf82 | pop64 r0 | 0x140725d72 35 | 0x14039cf87 | pop64 r16 | 0x14069504f 36 | 0x14039cf8c | pop64 r4 | 0x1406d0453 37 | 0x14039cf91 | pop64 r13 | 0x14069a8da 38 | 0x14039cf96 | pop64 r3 | 0x1406de987 39 | 0x14039cf9b | pop64 r2 | 0x140740966 40 | 0x14039cfa0 | pop64 r14 | 0x14076a534 41 | 0x14039cfa5 | pop64 r15 | 0x14073cc29 42 | 0x14039cfaa | push_imm64 0x1400148a2 | 0x1406b58aa 43 | 0x14039cfb6 | push64 r19 | 0x1407233bb 44 | 0x14039cfbb | add64 | 0x14065c9e4 45 | 0x14039cfbf | pop64 r23 | 0x14066b565 46 | 0x14039cfc4 | pop64 r24 | 0x1406c5fd7 47 | 0x14039cfc9 | pushvsp64 | 0x1406dd647 48 | 0x14039cfcd | pop64 r25 | 0x1406a0a37 49 | 0x14039cfd2 | push64 r3 | 0x1407504ba 50 | 0x14039cfd7 | pop64 r26 | 0x140725d72 51 | 0x14039cfdc | push64 r2 | 0x1406b0c5d 52 | 0x14039cfe1 | pop64 r27 | 0x14069504f 53 | 0x14039cfe6 | push64 r13 | 0x14073ce7e 54 | 0x14039cfeb | pop64 r28 | 0x1406d0453 55 | 0x14039cff0 | push64 r18 | 0x140776f28 56 | 0x14039cff5 | pop64 r29 | 0x14069a8da 57 | 0x14039cffa | push_imm64 0x1407962a0 | 0x14066ecc1 58 | 0x14039d006 | push_imm32 0x3 | 0x14068f1ea 59 | 0x14039d00e | pop32 r16_dword_0 | 0x14067b681 60 | 0x14039d013 | push_imm32 0x0 | 0x140756802 61 | 0x14039d01b | pop32 r16_dword_1 | 0x14068d4fe 62 | 0x14039d020 | push_imm64 0x140074b10 | 0x140720d16 63 | 0x14039d02c | push64 r19 | 0x140652822 64 | 0x14039d031 | add64 | 0x1406f2971 65 | 0x14039d035 | push64 r18 | 0x140720c6d 66 | 0x14039d03a | pop64 r23 | 0x1406de987 67 | 0x14039d03f | pop64 r20 | 0x140740966 68 | 0x14039d044 | pop64 r12 | 0x14076a534 69 | 0x14039d049 | push64 r19 | 0x1407612e8 70 | 0x14039d04e | add64 | 0x140723579 71 | 0x14039d052 | pop64 r15 | 0x14073cc29 72 | 0x14039d057 | push_imm64 0x140069068 | 0x140735929 73 | 0x14039d063 | push64 r19 | 0x1406953ee 74 | 0x14039d068 | add64 | 0x14071e780 75 | 0x14039d06c | pop64 r11 | 0x14066b565 76 | 0x14039d071 | fetch64 | 0x14071bcc3 77 | 0x14039d075 | push64 r2 | 0x140676a3e 78 | 0x14039d07a | push64 r3 | 0x140740fae 79 | 0x14039d07f | push64 r13 | 0x1407233bb 80 | 0x14039d084 | push64 r23 | 0x1407504ba 81 | 0x14039d089 | push64 r16 | 0x1406b0c5d 82 | 0x14039d08e | push64 r0 | 0x14073ce7e 83 | 0x14039d093 | push64 r5 | 0x140776f28 84 | 0x14039d098 | push64 r7 | 0x140652822 85 | 0x14039d09d | push64 r17 | 0x140720c6d 86 | 0x14039d0a2 | push64 r8 | 0x1407612e8 87 | 0x14039d0a7 | push64 r21 | 0x1406953ee 88 | 0x14039d0ac | push64 r22 | 0x140676a3e 89 | 0x14039d0b1 | push64 r12 | 0x140740fae 90 | 0x14039d0b6 | push64 r18 | 0x1407233bb 91 | 0x14039d0bb | push64 r9 | 0x1407504ba 92 | 0x14039d0c0 | push64 r10 | 0x1406b0c5d 93 | 0x14039d0c5 | vm_exit | 0x1406f0494 94 | Getting helper stub -> helperstub_14039cf47 95 | 96 | define i64 @helperfunction_14039cf47(i64* noalias %rax, i64* noalias %rbx, i64* noalias %rcx, i64* noalias %rdx, i64* noalias %rsi, i64* noalias %rdi, i64* noalias %rbp, i64* noalias %rsp, i64* noalias %r8, i64* noalias %r9, i64* noalias %r10, i64* noalias %r11, i64* noalias %r12, i64* noalias %r13, i64* noalias %r14, i64* noalias %r15, i64* noalias %flags, i64 %KEY_STUB, i64 %RET_ADDR, i64 %REL_ADDR) { 97 | call void @llvm.experimental.noalias.scope.decl(metadata !10) 98 | call void @llvm.experimental.noalias.scope.decl(metadata !13) 99 | call void @llvm.experimental.noalias.scope.decl(metadata !15) 100 | call void @llvm.experimental.noalias.scope.decl(metadata !17) 101 | call void @llvm.experimental.noalias.scope.decl(metadata !19) 102 | %1 = load i64, i64* %rsp, align 8, !tbaa !3, !alias.scope !19, !noalias !21 103 | %2 = add i64 %1, -8 104 | %3 = getelementptr inbounds [0 x i8], [0 x i8]* @RAM, i64 0, i64 %2 105 | %4 = bitcast i8* %3 to i64* 106 | %5 = load i64, i64* %rbx, align 8, !alias.scope !10, !noalias !36 107 | store i64 5376664224, i64* %4, align 1, !noalias !37 108 | %6 = load i64, i64* bitcast (i8* getelementptr inbounds ([0 x i8], [0 x i8]* @RAM, i64 0, i64 5369139304) to i64*), align 1, !noalias !37 109 | store i64 5369187088, i64* %r8, align 8, !tbaa !3, !alias.scope !17, !noalias !38 110 | store i64 3, i64* %rcx, align 8, !tbaa !3, !alias.scope !13, !noalias !39 111 | store i64 %5, i64* %rdx, align 8, !tbaa !3, !alias.scope !15, !noalias !40 112 | store i64 %2, i64* %rsp, align 8, !tbaa !3, !alias.scope !19, !noalias !21 113 | ret i64 %6 114 | } 115 | 116 | ``` 117 | 118 | # Open source software usage 119 | The c++ code that compiles to the llvm helper file was released by FvrMateo and is available here https://github.com/LLVMParty/TicklingVMProtect/tree/master/Helpers 120 | 121 | 122 | This project uses the following open source rust crates 123 | - iced_x86 https://github.com/icedland/iced 124 | - clap https://github.com/icedland/iced 125 | - pelite https://github.com/CasualX/pelite 126 | - haybale https://github.com/PLSysSec/haybale 127 | - inkwell https://github.com/TheDan64/inkwell 128 | - petgraph https://github.com/petgraph/petgraph 129 | 130 | The project also makes heavy use of llvm software 131 | 132 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet, VecDeque}; 2 | use std::error::Error; 3 | 4 | use pelite::pe64::PeFile; 5 | use pelite::FileMap; 6 | 7 | use clap::Parser; 8 | use std::io::Write; 9 | 10 | use petgraph::dot::Config; 11 | use petgraph::graphmap::GraphMap; 12 | use petgraph::visit::NodeRef; 13 | 14 | mod llvm_ir_gen; 15 | mod match_assembly; 16 | mod symbolic; 17 | mod transforms; 18 | mod util; 19 | mod vm_handler; 20 | mod vm_matchers; 21 | 22 | use vm_handler::VmContext; 23 | 24 | use crate::llvm_ir_gen::VmLifter; 25 | use crate::vm_matchers::HandlerVmInstruction; 26 | 27 | fn parse_hex_vm_call(input_str: &str) -> Result { 28 | let str_trimmed = input_str.trim_start_matches("0x"); 29 | u64::from_str_radix(str_trimmed, 16) 30 | } 31 | 32 | #[derive(Parser, Debug)] 33 | struct CommandLineArgs { 34 | /// Input file 35 | pub input_file: String, 36 | /// Vm call address 37 | /// Address of the push instruction in 38 | /// push 39 | /// call vm_entry 40 | #[clap(short, long, parse(try_from_str = parse_hex_vm_call))] 41 | pub vm_call_addresses: Vec, 42 | /// Max blocks for slicing 43 | #[clap(long)] 44 | pub max_blocks: Option, 45 | } 46 | 47 | fn main() -> Result<(), Box> { 48 | let command_line_args = CommandLineArgs::parse(); 49 | let input_file = &command_line_args.input_file; 50 | 51 | let map = FileMap::open(input_file)?; 52 | let pe_file = PeFile::from_bytes(&map)?; 53 | let pe_bytes = std::fs::read(input_file)?; 54 | 55 | // Create the `VmLifter` 56 | let vm_lifter = VmLifter::new(); 57 | 58 | // Lift all the functions specified 59 | for address in command_line_args.vm_call_addresses.iter().cloned() { 60 | explore_cfg_and_lift_function(&pe_file, &pe_bytes, address, &vm_lifter, command_line_args.max_blocks)?; 61 | } 62 | 63 | // We do not want to delete globals in this case as it messes up recompilation 64 | vm_lifter.optimize_module_no_global_delete(); 65 | 66 | 67 | for address in command_line_args.vm_call_addresses.iter().cloned() { 68 | // Fix the argument names since a stripping pass is included 69 | vm_lifter.fix_arg_names(&format!("helperfunction_{:x}", address)); 70 | 71 | // Print the function to stderr 72 | vm_lifter.print_function(&format!("helperfunction_{:x}", address)); 73 | } 74 | 75 | 76 | // Output the module to an ir file devirt.ll 77 | vm_lifter.output_module(); 78 | 79 | Ok(()) 80 | } 81 | 82 | fn explore_cfg_and_lift_function(pe_file: &PeFile, pe_bytes: &[u8], vm_call_address: u64, vm_lifter: &VmLifter, max_blocks: Option) -> Result<(), Box> { 83 | 84 | // Cfg exploration 85 | let mut explored = HashMap::new(); 86 | let mut worklist = VecDeque::new(); 87 | let mut reprove_list = VecDeque::new(); 88 | 89 | let mut control_flow_graph = GraphMap::::new(); 90 | 91 | 92 | // `VmContext` for the first block 93 | let mut vm_context = 94 | VmContext::new_from_vm_entry(pe_file, pe_bytes, vm_call_address); 95 | 96 | let root_vip = vm_context.initial_vip; 97 | 98 | // Disassemble the handlers 99 | let handlers = vm_context.disassemble_context(pe_file, pe_bytes); 100 | // Get the last handler 101 | let last_handler = *handlers.last().unwrap(); 102 | 103 | // Lift this first block into a stub 104 | vm_lifter.lift_helper_stub(&vm_context, &handlers); 105 | 106 | // Add the first block to the cfg 107 | control_flow_graph.add_node(root_vip); 108 | 109 | // Handle special case of the first block ending in nop 110 | if last_handler.1 == HandlerVmInstruction::Nop { 111 | 112 | worklist.push_back((vm_context.clone(), last_handler, vm_context.vip_value)); 113 | explored.insert(root_vip, (vm_context, last_handler)); 114 | 115 | } else if last_handler.1 != HandlerVmInstruction::VmExit { 116 | let next_vips = vm_lifter.slice_vip(&control_flow_graph, 117 | vm_context.initial_vip, 118 | root_vip, 119 | max_blocks)?; 120 | 121 | for target_vip in next_vips { 122 | worklist.push_back((vm_context.clone(), last_handler, target_vip)); 123 | explored.insert(root_vip, (vm_context.clone(), last_handler)); 124 | } 125 | } 126 | 127 | loop { 128 | // Print the current lists 129 | 130 | println!("Worklist {:#x?}", 131 | worklist.iter() 132 | .map(|(_, _, target)| target) 133 | .collect::>()); 134 | println!("Explored {:#x?}", explored.keys()); 135 | println!("Reprove {:#x?}", 136 | reprove_list.iter() 137 | .map(|(_, _, target)| target) 138 | .collect::>()); 139 | 140 | // If the worklist is empty extend it with the reprove list, if that is empty 141 | // we're done 142 | if worklist.is_empty() { 143 | if reprove_list.is_empty() { 144 | break; 145 | } else { 146 | while !reprove_list.is_empty() { 147 | let reprove = reprove_list.pop_front().unwrap(); 148 | worklist.push_back(reprove); 149 | } 150 | } 151 | } 152 | 153 | // Should never panic because we explicitly check that the list is not empty 154 | // first 155 | // Get an item from the worklist 156 | // Contains the vm_context of the handler that branched to current_block_vip 157 | // And the last handler that branched to current_block_vip 158 | // This iteration we start disassembling from current_block_vip 159 | let (prev_block_vm_context, last_prev_block_handler, current_block_vip) = 160 | worklist.pop_front().unwrap(); 161 | 162 | // Check if already visited 163 | if explored.contains_key(¤t_block_vip) { 164 | // Ok nothing to do because we already new about this edge 165 | if control_flow_graph.contains_edge(prev_block_vm_context.initial_vip, 166 | current_block_vip) 167 | { 168 | continue; 169 | } 170 | // Ok stuff to do because we did not know about this edge yet but it goes to a 171 | // block we did know about 172 | // 173 | // 174 | // Get the edges of the cfg that start from current_block_vip 175 | let outgoing_edges = 176 | control_flow_graph.edges_directed(current_block_vip, 177 | petgraph::EdgeDirection::Outgoing); 178 | 179 | // target contains the destination of the edge from current_block_vip 180 | for (_, target, _) in outgoing_edges { 181 | // Ok get all the blocks the current_block_vip block could branch to 182 | let target_block = explored.get(&target); 183 | 184 | match target_block { 185 | Some(entry) => {let (vm_context, last_handler) = entry; 186 | // Add them to the reprove list 187 | reprove_list.push_back((vm_context.clone(), *last_handler, target)); 188 | // We remove them from explored 189 | explored.remove(&target);}, 190 | None => { 191 | // Still in the worklist and not yet explored nothing to do 192 | }, 193 | } 194 | } 195 | } 196 | 197 | // Add the edge from the previous block to the current block 198 | println!("ADDING EDGE {:#x} -> {:#x}", 199 | prev_block_vm_context.initial_vip, current_block_vip); 200 | control_flow_graph.add_edge(prev_block_vm_context.initial_vip, current_block_vip, ()); 201 | 202 | // Ok we now explore this block so add it to explored 203 | explored.insert(current_block_vip, 204 | (prev_block_vm_context.clone(), last_prev_block_handler)); 205 | 206 | // This condition is here for the case of single block stubs 207 | if last_prev_block_handler.1 == HandlerVmInstruction::VmExit { 208 | continue; 209 | } 210 | 211 | // Debug printing 212 | println!("Previous vm_context start_vip -> {:#x}", 213 | prev_block_vm_context.initial_vip); 214 | println!("Getting vm_context at current_block_vip -> {:#x}", 215 | current_block_vip); 216 | 217 | let mut current_block_vm_context; 218 | 219 | // If the last block ended in a nop 220 | if last_prev_block_handler.1 == HandlerVmInstruction::Nop { 221 | current_block_vm_context = prev_block_vm_context; 222 | current_block_vm_context.initial_vip = current_block_vm_context.vip_value; 223 | } else { 224 | current_block_vm_context = 225 | prev_block_vm_context.new_from_jump_handler(&last_prev_block_handler, 226 | current_block_vip, 227 | pe_file, 228 | pe_bytes); 229 | } 230 | 231 | // Get the new handler of the current_block_vip block 232 | let current_block_handlers = 233 | current_block_vm_context.disassemble_context(pe_file, pe_bytes); 234 | 235 | // If this panics shit is fucked anyways 236 | let last_current_block_handler = *current_block_handlers.last().unwrap(); 237 | 238 | // Lift the new handlers into a helper stub 239 | vm_lifter.lift_helper_stub(¤t_block_vm_context, ¤t_block_handlers); 240 | 241 | // Skip slicing since exit 242 | if last_current_block_handler.1 == HandlerVmInstruction::VmExit { 243 | continue; 244 | } 245 | 246 | // Skip slicing because NOP 247 | if last_current_block_handler.1 == HandlerVmInstruction::Nop { 248 | let target_vip = current_block_vm_context.vip_value; 249 | println!("NOP target_vip -> {:#x}", target_vip); 250 | 251 | worklist.push_back((current_block_vm_context, last_current_block_handler, target_vip)); 252 | continue; 253 | } 254 | 255 | let next_vips = vm_lifter.slice_vip(&control_flow_graph, 256 | current_block_vm_context.initial_vip, 257 | root_vip, 258 | max_blocks)?; 259 | for next_vip in next_vips { 260 | worklist.push_back((current_block_vm_context.clone(), 261 | last_current_block_handler, 262 | next_vip)); 263 | println!("Next vip -> {:#x}", next_vip); 264 | } 265 | } 266 | 267 | // // Write out the control flow graph to a dot file 268 | // let mut dot_file = std::fs::File::create("cfg.dot")?; 269 | // writeln!(dot_file, 270 | // "{:?}", 271 | // petgraph::dot::Dot::with_attr_getters(&control_flow_graph, 272 | // &[Config::EdgeNoLabel, Config::NodeNoLabel], 273 | // &|_, _| { "".to_owned() }, 274 | // &|_, node_ref| { 275 | // format!("label = \"{:#x}\"", 276 | // node_ref.weight()) 277 | // }))?; 278 | 279 | // Create the final lifted function 280 | let helper_function = vm_lifter.create_helper_function(&control_flow_graph, root_vip, vm_call_address); 281 | Ok(()) 282 | } 283 | -------------------------------------------------------------------------------- /src/transforms.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::{Code, Instruction, Register}; 2 | 3 | use crate::util::check_full_reg_written; 4 | 5 | pub fn get_transform_for_instruction(instruction: &Instruction) -> Option { 6 | // Add the transform that represents this instruction to the transforms vec 7 | match instruction.code() { 8 | Code::Bswap_r16 => Some(Transform::ByteSwap16), 9 | Code::Bswap_r32 => Some(Transform::ByteSwap32), 10 | Code::Bswap_r64 => Some(Transform::ByteSwap64), 11 | 12 | Code::Sub_AL_imm8 => Some(Transform::SubtractConstant8(instruction.immediate8())), 13 | Code::Sub_rm8_imm8 => Some(Transform::SubtractConstant8(instruction.immediate8())), 14 | Code::Sub_AX_imm16 => Some(Transform::SubtractConstant16(instruction.immediate16())), 15 | Code::Sub_rm16_imm16 => Some(Transform::SubtractConstant16(instruction.immediate16())), 16 | Code::Sub_EAX_imm32 => Some(Transform::SubtractConstant32(instruction.immediate32())), 17 | Code::Sub_rm32_imm32 => Some(Transform::SubtractConstant32(instruction.immediate32())), 18 | Code::Sub_RAX_imm32 => Some(Transform::SubtractConstant64(instruction.immediate64())), 19 | Code::Sub_rm64_imm32 => Some(Transform::SubtractConstant64(instruction.immediate64())), 20 | 21 | Code::Add_AL_imm8 => Some(Transform::AddConstant8(instruction.immediate8())), 22 | Code::Add_rm8_imm8 => Some(Transform::AddConstant8(instruction.immediate8())), 23 | Code::Add_AX_imm16 => Some(Transform::AddConstant16(instruction.immediate16())), 24 | Code::Add_rm16_imm16 => Some(Transform::AddConstant16(instruction.immediate16())), 25 | Code::Add_EAX_imm32 => Some(Transform::AddConstant32(instruction.immediate32())), 26 | Code::Add_rm32_imm32 => Some(Transform::AddConstant32(instruction.immediate32())), 27 | Code::Add_RAX_imm32 => Some(Transform::AddConstant64(instruction.immediate64())), 28 | Code::Add_rm64_imm32 => Some(Transform::AddConstant64(instruction.immediate64())), 29 | 30 | Code::Neg_rm8 => Some(Transform::Negate8), 31 | Code::Neg_rm16 => Some(Transform::Negate16), 32 | Code::Neg_rm32 => Some(Transform::Negate32), 33 | Code::Neg_rm64 => Some(Transform::Negate64), 34 | 35 | Code::Not_rm8 => Some(Transform::Not8), 36 | Code::Not_rm16 => Some(Transform::Not16), 37 | Code::Not_rm32 => Some(Transform::Not32), 38 | Code::Not_rm64 => Some(Transform::Not64), 39 | 40 | Code::Rol_rm8_imm8 => Some(Transform::RotateLeft8(instruction.immediate8() as u32)), 41 | Code::Rol_rm16_imm8 => Some(Transform::RotateLeft16(instruction.immediate8() as u32)), 42 | Code::Rol_rm32_imm8 => Some(Transform::RotateLeft32(instruction.immediate8() as u32)), 43 | Code::Rol_rm64_imm8 => Some(Transform::RotateLeft64(instruction.immediate8() as u32)), 44 | 45 | Code::Ror_rm8_imm8 => Some(Transform::RotateRight8(instruction.immediate8() as u32)), 46 | Code::Ror_rm16_imm8 => Some(Transform::RotateRight16(instruction.immediate8() as u32)), 47 | Code::Ror_rm32_imm8 => Some(Transform::RotateRight32(instruction.immediate8() as u32)), 48 | Code::Ror_rm64_imm8 => Some(Transform::RotateRight64(instruction.immediate8() as u32)), 49 | 50 | Code::Rol_rm8_1 => Some(Transform::RotateLeft8(1u32)), 51 | Code::Rol_rm16_1 => Some(Transform::RotateLeft16(1u32)), 52 | Code::Rol_rm32_1 => Some(Transform::RotateLeft32(1u32)), 53 | Code::Rol_rm64_1 => Some(Transform::RotateLeft64(1u32)), 54 | 55 | Code::Ror_rm8_1 => Some(Transform::RotateRight8(1u32)), 56 | Code::Ror_rm16_1 => Some(Transform::RotateRight16(1u32)), 57 | Code::Ror_rm32_1 => Some(Transform::RotateRight32(1u32)), 58 | Code::Ror_rm64_1 => Some(Transform::RotateRight64(1u32)), 59 | 60 | Code::Inc_rm8 => Some(Transform::Increment8), 61 | Code::Inc_rm16 => Some(Transform::Increment16), 62 | Code::Inc_rm32 => Some(Transform::Increment32), 63 | Code::Inc_rm64 => Some(Transform::Increment64), 64 | 65 | Code::Dec_rm8 => Some(Transform::Decrement8), 66 | Code::Dec_rm16 => Some(Transform::Decrement16), 67 | Code::Dec_rm32 => Some(Transform::Decrement32), 68 | Code::Dec_rm64 => Some(Transform::Decrement64), 69 | 70 | Code::Xor_AL_imm8 => Some(Transform::XorConstant8(instruction.immediate8())), 71 | Code::Xor_rm8_imm8 => Some(Transform::XorConstant8(instruction.immediate8())), 72 | Code::Xor_AX_imm16 => Some(Transform::XorConstant16(instruction.immediate16())), 73 | Code::Xor_rm16_imm16 => Some(Transform::XorConstant16(instruction.immediate16())), 74 | Code::Xor_EAX_imm32 => Some(Transform::XorConstant32(instruction.immediate32())), 75 | Code::Xor_rm32_imm32 => Some(Transform::XorConstant32(instruction.immediate32())), 76 | Code::Xor_RAX_imm32 => Some(Transform::XorConstant64(instruction.immediate64())), 77 | Code::Xor_rm64_imm32 => Some(Transform::XorConstant64(instruction.immediate64())), 78 | _ => None, 79 | } 80 | } 81 | #[derive(Debug, Clone, Copy)] 82 | pub enum Transform { 83 | ByteSwap64, 84 | ByteSwap32, 85 | ByteSwap16, 86 | 87 | SubtractConstant64(u64), 88 | SubtractConstant32(u32), 89 | SubtractConstant16(u16), 90 | SubtractConstant8(u8), 91 | 92 | AddConstant64(u64), 93 | AddConstant32(u32), 94 | AddConstant16(u16), 95 | AddConstant8(u8), 96 | 97 | Negate64, 98 | Negate32, 99 | Negate16, 100 | Negate8, 101 | 102 | Not64, 103 | Not32, 104 | Not16, 105 | Not8, 106 | 107 | RotateLeft64(u32), 108 | RotateLeft32(u32), 109 | RotateLeft16(u32), 110 | RotateLeft8(u32), 111 | 112 | RotateRight64(u32), 113 | RotateRight32(u32), 114 | RotateRight16(u32), 115 | RotateRight8(u32), 116 | 117 | Increment64, 118 | Increment32, 119 | Increment16, 120 | Increment8, 121 | 122 | Decrement64, 123 | Decrement32, 124 | Decrement16, 125 | Decrement8, 126 | 127 | XorConstant64(u64), 128 | XorConstant32(u32), 129 | XorConstant16(u16), 130 | XorConstant8(u8), 131 | } 132 | 133 | pub trait EmulateTransform { 134 | fn emulate_transform(self, 135 | transform: Transform) 136 | -> Self; 137 | } 138 | 139 | impl EmulateTransform for u8 { 140 | fn emulate_transform(self, 141 | transform: Transform) 142 | -> Self { 143 | emulate_transform8(transform, self) 144 | } 145 | } 146 | 147 | impl EmulateTransform for u16 { 148 | fn emulate_transform(self, 149 | transform: Transform) 150 | -> Self { 151 | emulate_transform16(transform, self) 152 | } 153 | } 154 | 155 | impl EmulateTransform for u32 { 156 | fn emulate_transform(self, 157 | transform: Transform) 158 | -> Self { 159 | emulate_transform32(transform, self) 160 | } 161 | } 162 | 163 | impl EmulateTransform for u64 { 164 | fn emulate_transform(self, 165 | transform: Transform) 166 | -> Self { 167 | emulate_transform64(transform, self) 168 | } 169 | } 170 | 171 | pub trait EmulateEncryption { 172 | fn emulate_encryption<'a, I>(self, 173 | instruction_iter: I, 174 | rolling_key: &mut u64, 175 | encrypted_reg: Register) 176 | -> Self 177 | where I: Iterator; 178 | } 179 | 180 | impl EmulateEncryption for u64 { 181 | fn emulate_encryption<'a, I>(mut self, 182 | instruction_iter: I, 183 | rolling_key: &mut u64, 184 | encrypted_reg: Register) 185 | -> Self 186 | where I: Iterator 187 | { 188 | self ^= *rolling_key as u64; 189 | 190 | for instruction in 191 | instruction_iter.filter(|&insn| check_full_reg_written(insn, encrypted_reg)) 192 | { 193 | let transform = get_transform_for_instruction(instruction); 194 | 195 | if let Some(transform) = transform { 196 | self = self.emulate_transform(transform); 197 | } 198 | } 199 | 200 | *rolling_key ^= self as u64; 201 | 202 | self 203 | } 204 | } 205 | 206 | impl EmulateEncryption for u32 { 207 | fn emulate_encryption<'a, I>(mut self, 208 | instruction_iter: I, 209 | rolling_key: &mut u64, 210 | encrypted_reg: Register) 211 | -> Self 212 | where I: Iterator 213 | { 214 | self ^= *rolling_key as u32; 215 | 216 | for instruction in 217 | instruction_iter.filter(|&insn| check_full_reg_written(insn, encrypted_reg)) 218 | { 219 | let transform = get_transform_for_instruction(instruction); 220 | 221 | if let Some(transform) = transform { 222 | self = self.emulate_transform(transform); 223 | } 224 | } 225 | 226 | *rolling_key ^= self as u64; 227 | 228 | self 229 | } 230 | } 231 | 232 | impl EmulateEncryption for u16 { 233 | fn emulate_encryption<'a, I>(mut self, 234 | instruction_iter: I, 235 | rolling_key: &mut u64, 236 | encrypted_reg: Register) 237 | -> Self 238 | where I: Iterator 239 | { 240 | self ^= *rolling_key as u16; 241 | 242 | for instruction in 243 | instruction_iter.filter(|&insn| check_full_reg_written(insn, encrypted_reg)) 244 | { 245 | let transform = get_transform_for_instruction(instruction); 246 | 247 | if let Some(transform) = transform { 248 | self = self.emulate_transform(transform); 249 | } 250 | } 251 | 252 | *rolling_key ^= self as u64; 253 | 254 | self 255 | } 256 | } 257 | 258 | impl EmulateEncryption for u8 { 259 | fn emulate_encryption<'a, I>(mut self, 260 | instruction_iter: I, 261 | rolling_key: &mut u64, 262 | encrypted_reg: Register) 263 | -> Self 264 | where I: Iterator 265 | { 266 | self ^= *rolling_key as u8; 267 | 268 | for instruction in 269 | instruction_iter.filter(|&insn| check_full_reg_written(insn, encrypted_reg)) 270 | { 271 | let transform = get_transform_for_instruction(instruction); 272 | if let Some(transform) = transform { 273 | self = self.emulate_transform(transform); 274 | } 275 | } 276 | 277 | *rolling_key ^= self as u64; 278 | 279 | self 280 | } 281 | } 282 | 283 | fn emulate_transform64(transform: Transform, 284 | input: u64) 285 | -> u64 { 286 | match transform { 287 | Transform::ByteSwap64 => input.swap_bytes(), 288 | 289 | Transform::SubtractConstant64(amount) => input.wrapping_sub(amount), 290 | 291 | Transform::AddConstant64(amount) => input.wrapping_add(amount), 292 | 293 | Transform::XorConstant64(amount) => input ^ amount, 294 | 295 | Transform::Negate64 => (!input).wrapping_add(1), 296 | 297 | Transform::Not64 => !input, 298 | 299 | Transform::RotateLeft64(amount) => input.rotate_left(amount), 300 | 301 | Transform::RotateRight64(amount) => input.rotate_right(amount), 302 | 303 | Transform::Decrement64 => input.wrapping_sub(1), 304 | 305 | Transform::Increment64 => input.wrapping_add(1), 306 | _ => { 307 | dbg!(transform); 308 | unreachable!(); 309 | }, 310 | } 311 | } 312 | 313 | fn emulate_transform32(transform: Transform, 314 | input: u32) 315 | -> u32 { 316 | match transform { 317 | Transform::ByteSwap32 => input.swap_bytes(), 318 | 319 | Transform::SubtractConstant32(amount) => input.wrapping_sub(amount), 320 | 321 | Transform::AddConstant32(amount) => input.wrapping_add(amount), 322 | 323 | Transform::XorConstant32(amount) => input ^ amount, 324 | 325 | Transform::Negate32 => (!input).wrapping_add(1), 326 | 327 | Transform::Not32 => !input, 328 | 329 | Transform::RotateLeft32(amount) => input.rotate_left(amount), 330 | 331 | Transform::RotateRight32(amount) => input.rotate_right(amount), 332 | 333 | Transform::Decrement32 => input.wrapping_sub(1), 334 | 335 | Transform::Increment32 => input.wrapping_add(1), 336 | _ => { 337 | dbg!(transform); 338 | unreachable!(); 339 | }, 340 | } 341 | } 342 | 343 | fn emulate_transform16(transform: Transform, 344 | input: u16) 345 | -> u16 { 346 | match transform { 347 | Transform::ByteSwap16 => input.swap_bytes(), 348 | 349 | Transform::SubtractConstant16(amount) => input.wrapping_sub(amount), 350 | 351 | Transform::AddConstant16(amount) => input.wrapping_add(amount), 352 | 353 | Transform::XorConstant16(amount) => input ^ amount, 354 | 355 | Transform::Negate16 => (!input).wrapping_add(1), 356 | 357 | Transform::Not16 => !input, 358 | 359 | Transform::RotateLeft16(amount) => input.rotate_left(amount), 360 | 361 | Transform::RotateRight16(amount) => input.rotate_right(amount), 362 | 363 | Transform::Decrement16 => input.wrapping_sub(1), 364 | 365 | Transform::Increment16 => input.wrapping_add(1), 366 | _ => { 367 | dbg!(transform); 368 | unreachable!(); 369 | }, 370 | } 371 | } 372 | 373 | fn emulate_transform8(transform: Transform, 374 | input: u8) 375 | -> u8 { 376 | match transform { 377 | Transform::SubtractConstant8(amount) => input.wrapping_sub(amount), 378 | 379 | Transform::AddConstant8(amount) => input.wrapping_add(amount), 380 | 381 | Transform::XorConstant8(amount) => input ^ amount, 382 | 383 | Transform::Negate8 => (!input).wrapping_add(1), 384 | 385 | Transform::Not8 => !input, 386 | 387 | Transform::RotateLeft8(amount) => input.rotate_left(amount), 388 | 389 | Transform::RotateRight8(amount) => input.rotate_right(amount), 390 | 391 | Transform::Decrement8 => input.wrapping_sub(1), 392 | 393 | Transform::Increment8 => input.wrapping_add(1), 394 | _ => { 395 | dbg!(transform); 396 | unreachable!(); 397 | }, 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "atty" 16 | version = "0.2.14" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 19 | dependencies = [ 20 | "hermit-abi", 21 | "libc", 22 | "winapi 0.3.9", 23 | ] 24 | 25 | [[package]] 26 | name = "autocfg" 27 | version = "1.1.0" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 30 | 31 | [[package]] 32 | name = "bitflags" 33 | version = "1.3.2" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 36 | 37 | [[package]] 38 | name = "boolector" 39 | version = "0.4.3" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "5567f99e46c8f1f61624adafd2fdf4424b203d9fc5534368421725af17c5fd21" 42 | dependencies = [ 43 | "boolector-sys", 44 | "libc", 45 | ] 46 | 47 | [[package]] 48 | name = "boolector-sys" 49 | version = "0.7.1" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "5b082d1c14d94d734ad51bfb114f451bf6f1e1054dafae6ff00265d2fe5963e5" 52 | dependencies = [ 53 | "cc", 54 | "cmake", 55 | "copy_dir", 56 | "libc", 57 | ] 58 | 59 | [[package]] 60 | name = "cc" 61 | version = "1.0.73" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" 64 | 65 | [[package]] 66 | name = "cfg-if" 67 | version = "0.1.10" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 70 | 71 | [[package]] 72 | name = "cfg-if" 73 | version = "1.0.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 76 | 77 | [[package]] 78 | name = "clap" 79 | version = "3.2.6" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "9f1fe12880bae935d142c8702d500c63a4e8634b6c3c57ad72bf978fc7b6249a" 82 | dependencies = [ 83 | "atty", 84 | "bitflags", 85 | "clap_derive", 86 | "clap_lex", 87 | "indexmap", 88 | "once_cell", 89 | "strsim", 90 | "termcolor", 91 | "textwrap", 92 | ] 93 | 94 | [[package]] 95 | name = "clap_derive" 96 | version = "3.2.6" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "ed6db9e867166a43a53f7199b5e4d1f522a1e5bd626654be263c999ce59df39a" 99 | dependencies = [ 100 | "heck", 101 | "proc-macro-error", 102 | "proc-macro2", 103 | "quote", 104 | "syn", 105 | ] 106 | 107 | [[package]] 108 | name = "clap_lex" 109 | version = "0.2.3" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "87eba3c8c7f42ef17f6c659fc7416d0f4758cd3e58861ee63c5fa4a4dde649e4" 112 | dependencies = [ 113 | "os_str_bytes", 114 | ] 115 | 116 | [[package]] 117 | name = "cmake" 118 | version = "0.1.48" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" 121 | dependencies = [ 122 | "cc", 123 | ] 124 | 125 | [[package]] 126 | name = "copy_dir" 127 | version = "0.1.2" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "6e4281031634644843bd2f5aa9c48cf98fc48d6b083bd90bb11becf10deaf8b0" 130 | dependencies = [ 131 | "walkdir", 132 | ] 133 | 134 | [[package]] 135 | name = "cpp_demangle" 136 | version = "0.2.16" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "13c924384107361ca729c7d46b9134151b9a955ce99a773784f2777498e8552d" 139 | dependencies = [ 140 | "cfg-if 0.1.10", 141 | "glob", 142 | ] 143 | 144 | [[package]] 145 | name = "dataview" 146 | version = "0.1.2" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "47a802a2cad0ff4dfc4f3110da174b7a6928c315cae523e88638cfb72941b4d5" 149 | dependencies = [ 150 | "derive_pod", 151 | ] 152 | 153 | [[package]] 154 | name = "derive_pod" 155 | version = "0.1.1" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "2e2d4527fc8a6ad5cdb22622bed719d47f5e47f2e7b53cb821e1c933f62f3eca" 158 | 159 | [[package]] 160 | name = "either" 161 | version = "1.6.1" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 164 | 165 | [[package]] 166 | name = "fixedbitset" 167 | version = "0.4.1" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" 170 | 171 | [[package]] 172 | name = "glob" 173 | version = "0.3.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 176 | 177 | [[package]] 178 | name = "hashbrown" 179 | version = "0.12.1" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" 182 | 183 | [[package]] 184 | name = "haybale" 185 | version = "0.7.1" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "4fb3b65f04dd0aa507c6b98a3e7062ceb9a1f9fa67d61cf8fd29408113171418" 188 | dependencies = [ 189 | "boolector", 190 | "cpp_demangle", 191 | "either", 192 | "itertools", 193 | "llvm-ir", 194 | "log", 195 | "reduce", 196 | "rustc-demangle", 197 | "rustversion", 198 | ] 199 | 200 | [[package]] 201 | name = "heck" 202 | version = "0.4.0" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 205 | 206 | [[package]] 207 | name = "hermit-abi" 208 | version = "0.1.19" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 211 | dependencies = [ 212 | "libc", 213 | ] 214 | 215 | [[package]] 216 | name = "iced-x86" 217 | version = "1.17.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "158f5204401d08f91d19176112146d75e99b3cf745092e268fa7be33e09adcec" 220 | dependencies = [ 221 | "lazy_static", 222 | "static_assertions", 223 | ] 224 | 225 | [[package]] 226 | name = "indexmap" 227 | version = "1.9.1" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" 230 | dependencies = [ 231 | "autocfg", 232 | "hashbrown", 233 | ] 234 | 235 | [[package]] 236 | name = "inkwell" 237 | version = "0.1.0" 238 | source = "git+https://github.com/TheDan64/inkwell?branch=master#25b9fc5870370211504e874e7c81dc53573bca79" 239 | dependencies = [ 240 | "either", 241 | "inkwell_internals", 242 | "libc", 243 | "llvm-sys", 244 | "once_cell", 245 | "parking_lot", 246 | ] 247 | 248 | [[package]] 249 | name = "inkwell_internals" 250 | version = "0.5.0" 251 | source = "git+https://github.com/TheDan64/inkwell?branch=master#25b9fc5870370211504e874e7c81dc53573bca79" 252 | dependencies = [ 253 | "proc-macro2", 254 | "quote", 255 | "syn", 256 | ] 257 | 258 | [[package]] 259 | name = "itertools" 260 | version = "0.10.3" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 263 | dependencies = [ 264 | "either", 265 | ] 266 | 267 | [[package]] 268 | name = "kernel32-sys" 269 | version = "0.2.2" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 272 | dependencies = [ 273 | "winapi 0.2.8", 274 | "winapi-build", 275 | ] 276 | 277 | [[package]] 278 | name = "lazy_static" 279 | version = "1.4.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 282 | 283 | [[package]] 284 | name = "libc" 285 | version = "0.2.126" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" 288 | 289 | [[package]] 290 | name = "llvm-ir" 291 | version = "0.8.1" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "7f292d36cc01be049372faa8e5fb4aaa261d4875f7d5cdc59a86353434b7ed02" 294 | dependencies = [ 295 | "either", 296 | "llvm-sys", 297 | "log", 298 | ] 299 | 300 | [[package]] 301 | name = "llvm-sys" 302 | version = "130.0.4" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "bdb6ea20e8a348f6db0b43a7f009fa7d981d22edf4cbe2e0c7b2247dbb25be61" 305 | dependencies = [ 306 | "cc", 307 | "lazy_static", 308 | "libc", 309 | "regex", 310 | "semver", 311 | ] 312 | 313 | [[package]] 314 | name = "lock_api" 315 | version = "0.4.7" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" 318 | dependencies = [ 319 | "autocfg", 320 | "scopeguard", 321 | ] 322 | 323 | [[package]] 324 | name = "log" 325 | version = "0.4.17" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 328 | dependencies = [ 329 | "cfg-if 1.0.0", 330 | ] 331 | 332 | [[package]] 333 | name = "memchr" 334 | version = "2.5.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 337 | 338 | [[package]] 339 | name = "no-std-compat" 340 | version = "0.4.1" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" 343 | 344 | [[package]] 345 | name = "once_cell" 346 | version = "1.12.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" 349 | 350 | [[package]] 351 | name = "os_str_bytes" 352 | version = "6.1.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" 355 | 356 | [[package]] 357 | name = "parking_lot" 358 | version = "0.12.1" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 361 | dependencies = [ 362 | "lock_api", 363 | "parking_lot_core", 364 | ] 365 | 366 | [[package]] 367 | name = "parking_lot_core" 368 | version = "0.9.3" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" 371 | dependencies = [ 372 | "cfg-if 1.0.0", 373 | "libc", 374 | "redox_syscall", 375 | "smallvec", 376 | "windows-sys", 377 | ] 378 | 379 | [[package]] 380 | name = "pelite" 381 | version = "0.9.1" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "9f1510e9ff41f8de8db8e2c763af5f75ad0e45003cff34ed1ba134205db0c9fc" 384 | dependencies = [ 385 | "dataview", 386 | "libc", 387 | "no-std-compat", 388 | "pelite-macros", 389 | "winapi 0.3.9", 390 | ] 391 | 392 | [[package]] 393 | name = "pelite-macros" 394 | version = "0.1.1" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "7a7cf3f8ecebb0f4895f4892a8be0a0dc81b498f9d56735cb769dc31bf00815b" 397 | 398 | [[package]] 399 | name = "pest" 400 | version = "2.1.3" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" 403 | dependencies = [ 404 | "ucd-trie", 405 | ] 406 | 407 | [[package]] 408 | name = "petgraph" 409 | version = "0.6.2" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" 412 | dependencies = [ 413 | "fixedbitset", 414 | "indexmap", 415 | ] 416 | 417 | [[package]] 418 | name = "proc-macro-error" 419 | version = "1.0.4" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 422 | dependencies = [ 423 | "proc-macro-error-attr", 424 | "proc-macro2", 425 | "quote", 426 | "syn", 427 | "version_check", 428 | ] 429 | 430 | [[package]] 431 | name = "proc-macro-error-attr" 432 | version = "1.0.4" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 435 | dependencies = [ 436 | "proc-macro2", 437 | "quote", 438 | "version_check", 439 | ] 440 | 441 | [[package]] 442 | name = "proc-macro2" 443 | version = "1.0.40" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" 446 | dependencies = [ 447 | "unicode-ident", 448 | ] 449 | 450 | [[package]] 451 | name = "quote" 452 | version = "1.0.20" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" 455 | dependencies = [ 456 | "proc-macro2", 457 | ] 458 | 459 | [[package]] 460 | name = "redox_syscall" 461 | version = "0.2.13" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" 464 | dependencies = [ 465 | "bitflags", 466 | ] 467 | 468 | [[package]] 469 | name = "reduce" 470 | version = "0.1.4" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "16d2dc47b68ac15ea328cd7ebe01d7d512ed29787f7d534ad2a3c341328b35d7" 473 | 474 | [[package]] 475 | name = "regex" 476 | version = "1.5.6" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" 479 | dependencies = [ 480 | "aho-corasick", 481 | "memchr", 482 | "regex-syntax", 483 | ] 484 | 485 | [[package]] 486 | name = "regex-syntax" 487 | version = "0.6.26" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" 490 | 491 | [[package]] 492 | name = "rustc-demangle" 493 | version = "0.1.21" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" 496 | 497 | [[package]] 498 | name = "rustversion" 499 | version = "1.0.7" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" 502 | 503 | [[package]] 504 | name = "scopeguard" 505 | version = "1.1.0" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 508 | 509 | [[package]] 510 | name = "semver" 511 | version = "0.11.0" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 514 | dependencies = [ 515 | "semver-parser", 516 | ] 517 | 518 | [[package]] 519 | name = "semver-parser" 520 | version = "0.10.2" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 523 | dependencies = [ 524 | "pest", 525 | ] 526 | 527 | [[package]] 528 | name = "smallvec" 529 | version = "1.8.1" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" 532 | 533 | [[package]] 534 | name = "static_assertions" 535 | version = "1.1.0" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 538 | 539 | [[package]] 540 | name = "strsim" 541 | version = "0.10.0" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 544 | 545 | [[package]] 546 | name = "syn" 547 | version = "1.0.98" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" 550 | dependencies = [ 551 | "proc-macro2", 552 | "quote", 553 | "unicode-ident", 554 | ] 555 | 556 | [[package]] 557 | name = "termcolor" 558 | version = "1.1.3" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 561 | dependencies = [ 562 | "winapi-util", 563 | ] 564 | 565 | [[package]] 566 | name = "textwrap" 567 | version = "0.15.0" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 570 | 571 | [[package]] 572 | name = "ucd-trie" 573 | version = "0.1.3" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" 576 | 577 | [[package]] 578 | name = "unicode-ident" 579 | version = "1.0.1" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" 582 | 583 | [[package]] 584 | name = "version_check" 585 | version = "0.9.4" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 588 | 589 | [[package]] 590 | name = "vmp3_disasm" 591 | version = "0.1.0" 592 | dependencies = [ 593 | "clap", 594 | "haybale", 595 | "iced-x86", 596 | "inkwell", 597 | "pelite", 598 | "petgraph", 599 | ] 600 | 601 | [[package]] 602 | name = "walkdir" 603 | version = "0.1.8" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "c66c0b9792f0a765345452775f3adbd28dde9d33f30d13e5dcc5ae17cf6f3780" 606 | dependencies = [ 607 | "kernel32-sys", 608 | "winapi 0.2.8", 609 | ] 610 | 611 | [[package]] 612 | name = "winapi" 613 | version = "0.2.8" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 616 | 617 | [[package]] 618 | name = "winapi" 619 | version = "0.3.9" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 622 | dependencies = [ 623 | "winapi-i686-pc-windows-gnu", 624 | "winapi-x86_64-pc-windows-gnu", 625 | ] 626 | 627 | [[package]] 628 | name = "winapi-build" 629 | version = "0.1.1" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 632 | 633 | [[package]] 634 | name = "winapi-i686-pc-windows-gnu" 635 | version = "0.4.0" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 638 | 639 | [[package]] 640 | name = "winapi-util" 641 | version = "0.1.5" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 644 | dependencies = [ 645 | "winapi 0.3.9", 646 | ] 647 | 648 | [[package]] 649 | name = "winapi-x86_64-pc-windows-gnu" 650 | version = "0.4.0" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 653 | 654 | [[package]] 655 | name = "windows-sys" 656 | version = "0.36.1" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" 659 | dependencies = [ 660 | "windows_aarch64_msvc", 661 | "windows_i686_gnu", 662 | "windows_i686_msvc", 663 | "windows_x86_64_gnu", 664 | "windows_x86_64_msvc", 665 | ] 666 | 667 | [[package]] 668 | name = "windows_aarch64_msvc" 669 | version = "0.36.1" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" 672 | 673 | [[package]] 674 | name = "windows_i686_gnu" 675 | version = "0.36.1" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" 678 | 679 | [[package]] 680 | name = "windows_i686_msvc" 681 | version = "0.36.1" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" 684 | 685 | [[package]] 686 | name = "windows_x86_64_gnu" 687 | version = "0.36.1" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" 690 | 691 | [[package]] 692 | name = "windows_x86_64_msvc" 693 | version = "0.36.1" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" 696 | -------------------------------------------------------------------------------- /src/match_assembly.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::{Code, Instruction, OpKind, Register}; 2 | 3 | use crate::vm_handler::VmRegisterAllocation; 4 | 5 | pub fn match_pushfq(instruction: &Instruction) -> bool { 6 | if instruction.code() != Code::Pushfq { 7 | return false; 8 | } 9 | true 10 | } 11 | 12 | pub fn match_popfq(instruction: &Instruction) -> bool { 13 | if instruction.code() != Code::Popfq { 14 | return false; 15 | } 16 | true 17 | } 18 | 19 | pub fn match_ret(instruction: &Instruction) -> bool { 20 | if instruction.code() != Code::Retnq { 21 | return false; 22 | } 23 | true 24 | } 25 | 26 | pub fn match_not_reg(instruction: &Instruction, 27 | register: Register) 28 | -> bool { 29 | match instruction.code() { 30 | Code::Not_rm8 | Code::Not_rm16 | Code::Not_rm32 | Code::Not_rm64 31 | if instruction.op0_register().full_register() == register => 32 | { 33 | true 34 | }, 35 | _ => false, 36 | } 37 | } 38 | 39 | pub fn match_mov_reg_source(instruction: &Instruction, 40 | register: Register) 41 | -> bool { 42 | match instruction.code() { 43 | Code::Mov_r64_rm64 | 44 | Code::Mov_r32_rm32 | 45 | Code::Mov_r16_rm16 | 46 | Code::Mov_r8_rm8 | 47 | Code::Mov_rm64_r64 | 48 | Code::Mov_rm32_r32 | 49 | Code::Mov_rm16_r16 | 50 | Code::Mov_rm8_r8 => {}, 51 | _ => return false, 52 | } 53 | 54 | if instruction.op0_kind() != OpKind::Register { 55 | return false; 56 | } 57 | 58 | if instruction.op1_kind() != OpKind::Register { 59 | return false; 60 | } 61 | 62 | if instruction.op1_register() != register { 63 | return false; 64 | } 65 | 66 | true 67 | } 68 | 69 | #[allow(dead_code)] 70 | pub fn match_mov_reg2_in_reg1(instruction: &Instruction, 71 | reg1: Register, 72 | reg2: Register) 73 | -> Option { 74 | let instruction_size = match instruction.code() { 75 | Code::Mov_rm8_r8 => 1, 76 | Code::Mov_rm16_r16 => 2, 77 | Code::Mov_rm32_r32 => 4, 78 | Code::Mov_rm64_r64 => 8, 79 | Code::Mov_r8_rm8 => 1, 80 | Code::Mov_r16_rm16 => 2, 81 | Code::Mov_r32_rm32 => 4, 82 | Code::Mov_r64_rm64 => 8, 83 | _ => return None, 84 | }; 85 | 86 | if instruction.op0_kind() != OpKind::Register { 87 | return None; 88 | } 89 | 90 | if instruction.op1_kind() != OpKind::Register { 91 | return None; 92 | } 93 | 94 | if instruction.op0_register() != reg1 { 95 | return None; 96 | } 97 | 98 | if instruction.op1_register() != reg2 { 99 | return None; 100 | } 101 | 102 | Some(instruction_size) 103 | } 104 | 105 | /// Return size of the store in bytes 106 | pub fn match_store_reg2_in_reg1(instruction: &Instruction, 107 | reg1: Register, 108 | reg2: Register) 109 | -> Option { 110 | let instruction_size = match instruction.code() { 111 | Code::Mov_rm8_r8 => 1, 112 | Code::Mov_rm16_r16 => 2, 113 | Code::Mov_rm32_r32 => 4, 114 | Code::Mov_rm64_r64 => 8, 115 | _ => return None, 116 | }; 117 | 118 | if instruction.op0_kind() != OpKind::Memory { 119 | return None; 120 | } 121 | 122 | if instruction.op1_kind() != OpKind::Register { 123 | return None; 124 | } 125 | 126 | if instruction.memory_base().full_register() != reg1 { 127 | return None; 128 | } 129 | 130 | if instruction.op1_register().full_register() != reg2 { 131 | return None; 132 | } 133 | 134 | Some(instruction_size) 135 | } 136 | 137 | pub fn match_xchng_reg(instruction: &Instruction, 138 | reg: Register) 139 | -> bool { 140 | match instruction.code() { 141 | Code::Xchg_rm64_r64 | Code::Xchg_r64_RAX => { 142 | if (instruction.op0_register() == reg.full_register() || 143 | instruction.op1_register() == reg.full_register()) && 144 | instruction.op0_register() != instruction.op1_register() 145 | { 146 | true 147 | } else { 148 | false 149 | } 150 | }, 151 | _ => false, 152 | } 153 | } 154 | 155 | pub fn match_shl_reg_reg(instruction: &Instruction, 156 | reg: Register) 157 | -> bool { 158 | match instruction.code() { 159 | Code::Shl_rm8_CL | Code::Shl_rm16_CL | Code::Shl_rm32_CL | Code::Shl_rm64_CL 160 | if (instruction.op0_register().full_register() == reg.full_register()) => 161 | { 162 | true 163 | }, 164 | 165 | _ => false, 166 | } 167 | } 168 | 169 | pub fn match_shr_reg_reg(instruction: &Instruction, 170 | reg: Register) 171 | -> bool { 172 | match instruction.code() { 173 | Code::Shr_rm8_CL | Code::Shr_rm16_CL | Code::Shr_rm32_CL | Code::Shr_rm64_CL 174 | if (instruction.op0_register().full_register() == reg.full_register()) => 175 | { 176 | true 177 | }, 178 | 179 | _ => false, 180 | } 181 | } 182 | 183 | pub fn match_shrd_reg_reg(instruction: &Instruction, 184 | reg: Register) 185 | -> bool { 186 | match instruction.code() { 187 | Code::Shrd_rm16_r16_CL | Code::Shrd_rm32_r32_CL | Code::Shrd_rm64_r64_CL 188 | if (instruction.op0_register().full_register() == reg.full_register()) => 189 | { 190 | true 191 | }, 192 | 193 | _ => false, 194 | } 195 | } 196 | 197 | pub fn match_shld_reg_reg(instruction: &Instruction, 198 | reg: Register) 199 | -> bool { 200 | match instruction.code() { 201 | Code::Shld_rm16_r16_CL | Code::Shld_rm32_r32_CL | Code::Shld_rm64_r64_CL 202 | if (instruction.op0_register().full_register() == reg.full_register()) => 203 | { 204 | true 205 | }, 206 | 207 | _ => false, 208 | } 209 | } 210 | 211 | pub fn match_or_reg_reg(instruction: &Instruction, 212 | reg1: Register, 213 | reg2: Register) 214 | -> bool { 215 | match instruction.code() { 216 | Code::Or_rm8_r8 | 217 | Code::Or_rm16_r16 | 218 | Code::Or_rm32_r32 | 219 | Code::Or_rm64_r64 | 220 | Code::Or_r8_rm8 | 221 | Code::Or_r16_rm16 | 222 | Code::Or_r32_rm32 | 223 | Code::Or_r64_rm64 224 | if (instruction.op0_register().full_register() == reg1 && 225 | instruction.op1_register().full_register() == reg2) || 226 | (instruction.op0_register().full_register() == reg2 && 227 | instruction.op1_register().full_register() == reg1) => 228 | { 229 | true 230 | }, 231 | 232 | _ => false, 233 | } 234 | } 235 | 236 | pub fn match_and_reg_reg(instruction: &Instruction, 237 | reg1: Register, 238 | reg2: Register) 239 | -> bool { 240 | match instruction.code() { 241 | Code::And_rm8_r8 | 242 | Code::And_rm16_r16 | 243 | Code::And_rm32_r32 | 244 | Code::And_rm64_r64 | 245 | Code::And_r8_rm8 | 246 | Code::And_r16_rm16 | 247 | Code::And_r32_rm32 | 248 | Code::And_r64_rm64 249 | if (instruction.op0_register().full_register() == reg1 && 250 | instruction.op1_register().full_register() == reg2) || 251 | (instruction.op0_register().full_register() == reg2 && 252 | instruction.op1_register().full_register() == reg1) => 253 | { 254 | true 255 | }, 256 | 257 | _ => false, 258 | } 259 | } 260 | 261 | pub fn match_add_reg_reg(instruction: &Instruction, 262 | reg1: Register, 263 | reg2: Register) 264 | -> bool { 265 | match instruction.code() { 266 | Code::Add_rm8_r8 | 267 | Code::Add_rm16_r16 | 268 | Code::Add_rm32_r32 | 269 | Code::Add_rm64_r64 | 270 | Code::Add_r8_rm8 | 271 | Code::Add_r16_rm16 | 272 | Code::Add_r32_rm32 | 273 | Code::Add_r64_rm64 274 | if (instruction.op0_register().full_register() == reg1 && 275 | instruction.op1_register().full_register() == reg2) || 276 | (instruction.op0_register().full_register() == reg2 && 277 | instruction.op1_register().full_register() == reg1) => 278 | { 279 | true 280 | }, 281 | 282 | _ => false, 283 | } 284 | } 285 | 286 | pub fn match_mul_reg_reg(instruction: &Instruction, 287 | reg1: Register, 288 | reg2: Register) 289 | -> bool { 290 | match instruction.code() { 291 | Code::Mul_rm64 | Code::Mul_rm32 | Code::Mul_rm16 | Code::Mul_rm8 292 | if (instruction.op0_register().full_register() == reg1 || 293 | instruction.op0_register().full_register() == reg2) => 294 | { 295 | true 296 | }, 297 | 298 | _ => false, 299 | } 300 | } 301 | 302 | pub fn match_sub_reg_left(instruction: &Instruction, 303 | reg1: Register) 304 | -> bool { 305 | match instruction.code() { 306 | Code::Sub_rm8_r8 | 307 | Code::Sub_rm16_r16 | 308 | Code::Sub_rm32_r32 | 309 | Code::Sub_rm64_r64 | 310 | Code::Sub_r8_rm8 | 311 | Code::Sub_r16_rm16 | 312 | Code::Sub_r32_rm32 | 313 | Code::Sub_r64_rm64 314 | if (instruction.op0_register().full_register() == reg1) => 315 | { 316 | true 317 | }, 318 | 319 | _ => false, 320 | } 321 | } 322 | 323 | pub fn match_imul_reg_reg(instruction: &Instruction, 324 | reg1: Register, 325 | reg2: Register) 326 | -> bool { 327 | match instruction.code() { 328 | Code::Imul_rm64 | Code::Imul_rm32 | Code::Imul_rm16 | Code::Imul_rm8 329 | if (instruction.op0_register().full_register() == reg1 || 330 | instruction.op0_register().full_register() == reg2) => 331 | { 332 | true 333 | }, 334 | 335 | _ => false, 336 | } 337 | } 338 | 339 | /// Returns the size of the match in bytes if there is one 340 | pub fn match_fetch_reg_any_size(instruction: &Instruction, 341 | register: Register) 342 | -> Option { 343 | let mov_size = match instruction.code() { 344 | Code::Mov_r64_rm64 if instruction.op1_kind() == OpKind::Memory => Some(8), 345 | Code::Mov_r32_rm32 if instruction.op1_kind() == OpKind::Memory => Some(4), 346 | Code::Mov_r16_rm16 if instruction.op1_kind() == OpKind::Memory => Some(2), 347 | Code::Mov_r8_rm8 if instruction.op1_kind() == OpKind::Memory => Some(1), 348 | Code::Movzx_r16_rm8 if instruction.op1_kind() == OpKind::Memory => Some(2), 349 | Code::Movzx_r32_rm8 if instruction.op1_kind() == OpKind::Memory => Some(4), 350 | Code::Movzx_r64_rm8 if instruction.op1_kind() == OpKind::Memory => Some(8), 351 | Code::Movzx_r16_rm16 if instruction.op1_kind() == OpKind::Memory => Some(2), 352 | Code::Movzx_r32_rm16 if instruction.op1_kind() == OpKind::Memory => Some(4), 353 | Code::Movzx_r64_rm16 if instruction.op1_kind() == OpKind::Memory => Some(8), 354 | _ => return None, 355 | }; 356 | 357 | if mov_size.is_some() { 358 | if instruction.memory_base().full_register() == register { 359 | mov_size 360 | } else { 361 | None 362 | } 363 | } else { 364 | None 365 | } 366 | } 367 | 368 | pub fn match_fetch_zx_reg_any_size(instruction: &Instruction, 369 | register: Register) 370 | -> Option { 371 | let mov_size = match instruction.code() { 372 | Code::Movzx_r64_rm8 if instruction.op1_kind() == OpKind::Memory => Some(1), 373 | Code::Movzx_r64_rm16 if instruction.op1_kind() == OpKind::Memory => Some(2), 374 | Code::Movzx_r32_rm8 if instruction.op1_kind() == OpKind::Memory => Some(1), 375 | Code::Movzx_r32_rm16 if instruction.op1_kind() == OpKind::Memory => Some(2), 376 | Code::Movzx_r16_rm8 if instruction.op1_kind() == OpKind::Memory => Some(1), 377 | Code::Movzx_r16_rm16 if instruction.op1_kind() == OpKind::Memory => Some(2), 378 | _ => return None, 379 | }; 380 | 381 | if mov_size.is_some() { 382 | if instruction.memory_base().full_register() == register { 383 | mov_size 384 | } else { 385 | None 386 | } 387 | } else { 388 | None 389 | } 390 | } 391 | 392 | pub fn match_store_reg_any_size(instruction: &Instruction, 393 | register: Register) 394 | -> Option { 395 | let mov_size = match instruction.code() { 396 | Code::Mov_rm64_r64 if instruction.op0_kind() == OpKind::Memory => Some(8), 397 | Code::Mov_rm32_r32 if instruction.op0_kind() == OpKind::Memory => Some(4), 398 | Code::Mov_rm16_r16 if instruction.op0_kind() == OpKind::Memory => Some(2), 399 | Code::Mov_rm8_r8 if instruction.op0_kind() == OpKind::Memory => Some(1), 400 | _ => return None, 401 | }; 402 | 403 | if mov_size.is_some() { 404 | if instruction.memory_base().full_register() == register { 405 | mov_size 406 | } else { 407 | None 408 | } 409 | } else { 410 | None 411 | } 412 | } 413 | 414 | pub fn match_fetch_vm_reg(instruction: &Instruction, 415 | index_reg: Register) 416 | -> bool { 417 | // Check the instruction opcode 418 | if instruction.code() != Code::Mov_r64_rm64 && 419 | instruction.code() != Code::Mov_r32_rm32 && 420 | instruction.code() != Code::Mov_r16_rm16 && 421 | instruction.code() != Code::Mov_r8_rm8 422 | { 423 | return false; 424 | } 425 | // Check that the second operand is a memory type operand 426 | if instruction.op1_kind() != OpKind::Memory { 427 | return false; 428 | } 429 | 430 | // Check that the displacement is 0 431 | if instruction.memory_displacement64() != 0x0 { 432 | return false; 433 | } 434 | 435 | // Check that the index register is rsp 436 | if instruction.memory_base() != Register::RSP { 437 | return false; 438 | } 439 | 440 | // Check that the index register is index_reg 441 | if instruction.memory_index() != index_reg { 442 | return false; 443 | } 444 | 445 | true 446 | } 447 | 448 | pub fn match_store_vm_reg(instruction: &Instruction, 449 | index_reg: Register) 450 | -> bool { 451 | // Check the instruction opcode 452 | if instruction.code() != Code::Mov_rm64_r64 && 453 | instruction.code() != Code::Mov_rm32_r32 && 454 | instruction.code() != Code::Mov_rm16_r16 && 455 | instruction.code() != Code::Mov_rm8_r8 456 | { 457 | return false; 458 | } 459 | // Check that the second operand is a memory type operand 460 | if instruction.op0_kind() != OpKind::Memory { 461 | return false; 462 | } 463 | 464 | // Check that the displacement is 0 465 | if instruction.memory_displacement64() != 0x0 { 466 | return false; 467 | } 468 | 469 | // Check that the index register is rsp 470 | if instruction.memory_base() != Register::RSP { 471 | return false; 472 | } 473 | 474 | // Check that the index register is index_reg 475 | if instruction.memory_index() != index_reg { 476 | return false; 477 | } 478 | 479 | true 480 | } 481 | 482 | pub fn match_fetch_encrypted_vip(instruction: &Instruction, 483 | vm_register_allocation: &VmRegisterAllocation) 484 | -> bool { 485 | // Check the instruction opcode 486 | if instruction.code() != Code::Mov_r64_rm64 { 487 | return false; 488 | } 489 | 490 | // Check that the second operand is a memory type operand 491 | if instruction.op1_kind() != OpKind::Memory { 492 | return false; 493 | } 494 | 495 | // Check that the displacement is 90 496 | if instruction.memory_displacement64() != 0x90 { 497 | return false; 498 | } 499 | 500 | // Check that the index register is rsp 501 | if instruction.memory_base() != Register::RSP { 502 | return false; 503 | } 504 | 505 | // Check that the write is to vip 506 | if instruction.op0_register() != vm_register_allocation.vip.into() { 507 | return false; 508 | } 509 | 510 | true 511 | } 512 | 513 | pub fn match_fetch_vip(instruction: &Instruction, 514 | vm_register_allocation: &VmRegisterAllocation) 515 | -> bool { 516 | if instruction.code() != Code::Mov_r32_rm32 { 517 | return false; 518 | } 519 | 520 | if instruction.op1_kind() != OpKind::Memory { 521 | return false; 522 | } 523 | 524 | if instruction.memory_base() != vm_register_allocation.vip.into() { 525 | return false; 526 | } 527 | 528 | true 529 | } 530 | 531 | pub fn match_push_rolling_key(instruction: &Instruction, 532 | vm_register_allocation: &VmRegisterAllocation) 533 | -> bool { 534 | if instruction.code() != Code::Push_r64 { 535 | return false; 536 | } 537 | 538 | if instruction.op0_kind() != OpKind::Register { 539 | return false; 540 | } 541 | 542 | if instruction.op0_register().full_register() != vm_register_allocation.key.into() { 543 | return false; 544 | } 545 | 546 | true 547 | } 548 | 549 | pub fn match_add_vsp_by_amount(instruction: &Instruction, 550 | vm_register_allocation: &VmRegisterAllocation, 551 | amount: u32) 552 | -> bool { 553 | if instruction.code() != Code::Add_rm64_imm32 { 554 | return false; 555 | } 556 | 557 | if instruction.immediate32() != amount { 558 | return false; 559 | } 560 | 561 | if instruction.op0_kind() != OpKind::Register { 562 | return false; 563 | } 564 | 565 | if instruction.op0_register().full_register() != vm_register_allocation.vsp.into() { 566 | return false; 567 | } 568 | 569 | true 570 | } 571 | 572 | pub fn match_sub_vsp_by_amount(instruction: &Instruction, 573 | vm_register_allocation: &VmRegisterAllocation, 574 | amount: u32) 575 | -> bool { 576 | if instruction.code() != Code::Sub_rm64_imm32 { 577 | return false; 578 | } 579 | 580 | if instruction.immediate32() != amount { 581 | return false; 582 | } 583 | 584 | if instruction.op0_kind() != OpKind::Register { 585 | return false; 586 | } 587 | 588 | if instruction.op0_register().full_register() != vm_register_allocation.vsp.into() { 589 | return false; 590 | } 591 | 592 | true 593 | } 594 | 595 | pub fn match_sub_reg_by_amount(instruction: &Instruction, 596 | reg: Register, 597 | amount: u32) 598 | -> bool { 599 | if instruction.code() != Code::Sub_rm64_imm32 { 600 | return false; 601 | } 602 | 603 | if instruction.immediate32() != amount { 604 | return false; 605 | } 606 | 607 | if instruction.op0_kind() != OpKind::Register { 608 | return false; 609 | } 610 | 611 | if instruction.op0_register().full_register() != reg.full_register() { 612 | return false; 613 | } 614 | 615 | true 616 | } 617 | 618 | pub fn match_add_reg_by_amount(instruction: &Instruction, 619 | reg: Register, 620 | amount: u32) 621 | -> bool { 622 | if instruction.code() != Code::Add_rm64_imm32 { 623 | return false; 624 | } 625 | 626 | if instruction.immediate32() != amount { 627 | return false; 628 | } 629 | 630 | if instruction.op0_kind() != OpKind::Register { 631 | return false; 632 | } 633 | 634 | if instruction.op0_register().full_register() != reg.full_register() { 635 | return false; 636 | } 637 | 638 | true 639 | } 640 | 641 | pub fn match_sub_vsp_get_amount(instruction: &Instruction, 642 | vm_register_allocation: &VmRegisterAllocation) 643 | -> Option { 644 | if instruction.code() != Code::Sub_rm64_imm32 { 645 | return None; 646 | } 647 | 648 | if instruction.op0_kind() != OpKind::Register { 649 | return None; 650 | } 651 | 652 | if instruction.op0_register().full_register() != vm_register_allocation.vsp.into() { 653 | return None; 654 | } 655 | 656 | Some(instruction.immediate32()) 657 | } 658 | 659 | pub fn match_add_vsp_get_amount(instruction: &Instruction, 660 | vm_register_allocation: &VmRegisterAllocation) 661 | -> Option { 662 | if instruction.code() != Code::Add_rm64_imm32 { 663 | return None; 664 | } 665 | 666 | if instruction.op0_kind() != OpKind::Register { 667 | return None; 668 | } 669 | 670 | if instruction.op0_register().full_register() != vm_register_allocation.vsp.into() { 671 | return None; 672 | } 673 | 674 | Some(instruction.immediate32()) 675 | } 676 | 677 | pub fn match_xor_64_rolling_key_source(instruction: &Instruction, 678 | vm_register_allocation: &VmRegisterAllocation) 679 | -> bool { 680 | if instruction.code() != Code::Xor_r64_rm64 { 681 | return false; 682 | } 683 | 684 | if instruction.op0_kind() != OpKind::Register { 685 | return false; 686 | } 687 | 688 | if instruction.op1_kind() != OpKind::Register { 689 | return false; 690 | } 691 | 692 | if instruction.op1_register().full_register() != vm_register_allocation.key.into() { 693 | return false; 694 | } 695 | 696 | true 697 | } 698 | 699 | pub fn match_xor_64_rolling_key_dest(instruction: &Instruction, 700 | vm_register_allocation: &VmRegisterAllocation) 701 | -> bool { 702 | if instruction.code() != Code::Xor_r64_rm64 { 703 | return false; 704 | } 705 | 706 | if instruction.op0_kind() != OpKind::Register { 707 | return false; 708 | } 709 | 710 | if instruction.op1_kind() != OpKind::Register { 711 | return false; 712 | } 713 | 714 | if instruction.op0_register().full_register() != vm_register_allocation.key.into() { 715 | return false; 716 | } 717 | 718 | true 719 | } 720 | 721 | pub fn match_xor_16_rolling_key_source(instruction: &Instruction, 722 | vm_register_allocation: &VmRegisterAllocation) 723 | -> bool { 724 | if instruction.code() != Code::Xor_r16_rm16 { 725 | return false; 726 | } 727 | 728 | if instruction.op0_kind() != OpKind::Register { 729 | return false; 730 | } 731 | 732 | if instruction.op1_kind() != OpKind::Register { 733 | return false; 734 | } 735 | 736 | if instruction.op1_register().full_register() != vm_register_allocation.key.into() { 737 | return false; 738 | } 739 | 740 | true 741 | } 742 | 743 | pub fn match_xor_16_rolling_key_dest(instruction: &Instruction, 744 | vm_register_allocation: &VmRegisterAllocation) 745 | -> bool { 746 | if instruction.code() != Code::Xor_r16_rm16 { 747 | return false; 748 | } 749 | 750 | if instruction.op0_kind() != OpKind::Register { 751 | return false; 752 | } 753 | 754 | if instruction.op1_kind() != OpKind::Register { 755 | return false; 756 | } 757 | 758 | if instruction.op0_register().full_register() != vm_register_allocation.key.into() { 759 | return false; 760 | } 761 | 762 | true 763 | } 764 | 765 | pub fn match_xor_32_rolling_key_source(instruction: &Instruction, 766 | vm_register_allocation: &VmRegisterAllocation) 767 | -> bool { 768 | if instruction.code() != Code::Xor_r32_rm32 { 769 | return false; 770 | } 771 | 772 | if instruction.op0_kind() != OpKind::Register { 773 | return false; 774 | } 775 | 776 | if instruction.op1_kind() != OpKind::Register { 777 | return false; 778 | } 779 | 780 | if instruction.op1_register().full_register() != vm_register_allocation.key.into() { 781 | return false; 782 | } 783 | 784 | true 785 | } 786 | pub fn match_xor_8_rolling_key_source(instruction: &Instruction, 787 | vm_register_allocation: &VmRegisterAllocation) 788 | -> bool { 789 | if instruction.code() != Code::Xor_r8_rm8 { 790 | return false; 791 | } 792 | 793 | if instruction.op0_kind() != OpKind::Register { 794 | return false; 795 | } 796 | 797 | if instruction.op1_kind() != OpKind::Register { 798 | return false; 799 | } 800 | 801 | if instruction.op1_register().full_register() != vm_register_allocation.key.into() { 802 | return false; 803 | } 804 | 805 | true 806 | } 807 | 808 | pub fn match_xor_8_rolling_key_dest(instruction: &Instruction, 809 | vm_register_allocation: &VmRegisterAllocation) 810 | -> bool { 811 | if instruction.code() != Code::Xor_r8_rm8 { 812 | return false; 813 | } 814 | 815 | if instruction.op0_kind() != OpKind::Register { 816 | return false; 817 | } 818 | 819 | if instruction.op1_kind() != OpKind::Register { 820 | return false; 821 | } 822 | 823 | if instruction.op0_register().full_register() != vm_register_allocation.key.into() { 824 | return false; 825 | } 826 | 827 | true 828 | } 829 | -------------------------------------------------------------------------------- /src/vm_handler.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | match_assembly::*, 3 | transforms::{get_transform_for_instruction, EmulateEncryption, EmulateTransform}, 4 | util::*, 5 | vm_matchers::{self, HandlerClass, HandlerVmInstruction}, 6 | }; 7 | use iced_x86::{Code, Instruction, OpKind, Register}; 8 | use pelite::pe64::PeFile; 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct VmRegisterAllocation { 12 | pub vip: Registers, 13 | pub vsp: Registers, 14 | pub key: Registers, 15 | pub handler_address: Registers, 16 | } 17 | 18 | /// Describes a vm context that is it holds the internal state and the register 19 | /// allocation of the vm, the register allocation changes between jumps, so a 20 | /// new VmContext needs to be made when a jump occurs 21 | #[derive(Debug, Clone)] 22 | pub struct VmContext { 23 | /// Register allocation of the vm 24 | pub register_allocation: VmRegisterAllocation, 25 | /// VmEntry address 26 | pub vm_entry_address: u64, 27 | /// Pushed value 28 | pub pushed_val: u64, 29 | /// Vip direction 30 | pub vip_direction_forwards: bool, 31 | /// Register push order 32 | pub push_order: Vec, 33 | /// Key value 34 | pub rolling_key: u64, 35 | /// Current vip 36 | pub vip_value: u64, 37 | /// Initial vip 38 | pub initial_vip: u64, 39 | /// Next handler address 40 | pub handler_address: u64, 41 | /// Reloc value 42 | pub reloc_value: u64, 43 | /// Address of call into the vm 44 | pub vm_call_address: u64, 45 | } 46 | 47 | impl VmContext { 48 | /// Create a new VmContext from a vm_entry handler 49 | pub fn new_from_vm_entry(pe_file: &PeFile, 50 | pe_bytes: &[u8], 51 | vm_call_address: u64) 52 | -> Self { 53 | // Get the pushed value and the vm entry handler address 54 | let (pushed_val, vm_entry_address) = handle_vm_call(pe_file, pe_bytes, vm_call_address); 55 | 56 | // Collect the instructions of the vm_entry into a VmHandler 57 | let vm_entry_handler = VmHandler::new(vm_entry_address, pe_file, pe_bytes); 58 | 59 | // Get the native register push order 60 | let push_order = vm_entry_handler.get_push_order_vm_entry(); 61 | 62 | let register_allocation = vm_entry_handler.get_register_allocation_vm_entry(); 63 | 64 | let direction_is_forwards = vm_entry_handler.determine_is_forwards(®ister_allocation); 65 | 66 | // Get the initial_vip 67 | let initial_vip = 68 | vm_entry_handler.get_initial_vip(®ister_allocation, pushed_val) + 0x100000000; 69 | 70 | let mut vip = initial_vip; 71 | 72 | // Rolling key is initialized to the initial vip 73 | let mut rolling_key = initial_vip; 74 | 75 | // Get the handler base address value 76 | let instruction_iter = vm_entry_handler.instructions.iter(); 77 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 78 | !(insn.code() == Code::Lea_r64_m && 79 | insn.memory_displacement64() != 0 && 80 | // This is to fix devirtualizeme 81 | insn.memory_displacement64() != 82 | 0x100000000) 83 | }); 84 | let handler_base_address = instruction_iter.next().unwrap().memory_displacement64(); 85 | 86 | let mut instruction_iter = 87 | instruction_iter.skip_while(|insn| !match_fetch_vip(insn, ®ister_allocation)); 88 | 89 | // Get the reg where the encrypted offset has been loaded into 90 | let encrypted_offset_reg = instruction_iter.next().unwrap().op0_register(); 91 | 92 | let encrypted_offset = fetch_dword_vip(pe_file, pe_bytes, &mut vip, direction_is_forwards); 93 | 94 | let encryption_iter = instruction_iter.take_while(|&insn| { 95 | !(match_push_rolling_key(insn, 96 | ®ister_allocation)) 97 | }); 98 | 99 | let unencrypted_offset = encrypted_offset.emulate_encryption(encryption_iter, 100 | &mut rolling_key, 101 | encrypted_offset_reg); 102 | 103 | // hmmm yes 104 | // movsxd offset_reg, offset_reg_32 105 | // add handler_base, offset_reg 106 | let next_handler_address = 107 | handler_base_address.wrapping_add(unencrypted_offset as i32 as i64 as u64); 108 | 109 | let vip_value = vip; 110 | 111 | //TODO support different relocs 112 | let reloc_value = 0; 113 | Self { register_allocation, 114 | vm_entry_address, 115 | pushed_val, 116 | vip_direction_forwards: direction_is_forwards, 117 | push_order, 118 | rolling_key, 119 | vip_value, 120 | initial_vip, 121 | handler_address: next_handler_address, 122 | reloc_value, 123 | vm_call_address } 124 | } 125 | 126 | pub fn new_from_jump_handler(&self, 127 | last_handler: &(u64, HandlerVmInstruction, u64), 128 | jump_target_vip: u64, 129 | pe_file: &PeFile, 130 | pe_bytes: &[u8]) 131 | -> Self { 132 | let jump_handler_address = last_handler.2; 133 | let (direction_is_forwards, changed_vsp) = match last_handler.1 { 134 | HandlerVmInstruction::JumpDecVspXchng => (false, true), 135 | HandlerVmInstruction::JumpIncVspXchng => (true, true), 136 | HandlerVmInstruction::JumpDecVspChange => (false, true), 137 | HandlerVmInstruction::JumpIncVspChange => (true, true), 138 | HandlerVmInstruction::JumpDec => (false, false), 139 | HandlerVmInstruction::JumpInc => (true, false), 140 | HandlerVmInstruction::Nop => (self.vip_direction_forwards, false), 141 | _ => panic!("Not a branch instruction"), 142 | }; 143 | 144 | let mut new_vm_context = self.clone(); 145 | 146 | let vm_jump_handler = VmHandler::new(jump_handler_address, pe_file, pe_bytes); 147 | 148 | match last_handler.1 { 149 | HandlerVmInstruction::JumpDecVspXchng => { 150 | vm_jump_handler.get_register_allocation_vm_jump_xchng( 151 | &mut new_vm_context.register_allocation); 152 | }, 153 | HandlerVmInstruction::JumpIncVspXchng => { 154 | vm_jump_handler.get_register_allocation_vm_jump_xchng( 155 | &mut new_vm_context.register_allocation); 156 | }, 157 | HandlerVmInstruction::JumpDecVspChange => { 158 | vm_jump_handler.get_register_allocation_vm_jump(changed_vsp, 159 | &mut new_vm_context.register_allocation); 160 | }, 161 | HandlerVmInstruction::JumpIncVspChange => { 162 | vm_jump_handler.get_register_allocation_vm_jump(changed_vsp, 163 | &mut new_vm_context.register_allocation); 164 | }, 165 | HandlerVmInstruction::JumpDec => { 166 | vm_jump_handler.get_register_allocation_vm_jump(changed_vsp, 167 | &mut new_vm_context.register_allocation); 168 | }, 169 | HandlerVmInstruction::JumpInc => { 170 | vm_jump_handler.get_register_allocation_vm_jump(changed_vsp, 171 | &mut new_vm_context.register_allocation); 172 | }, 173 | HandlerVmInstruction::Nop => {}, 174 | _ => panic!("Not a branch instruction"), 175 | }; 176 | println!("{:#x?}", new_vm_context); 177 | // Rolling key is initialized to the initial vip 178 | let mut vip = if direction_is_forwards { 179 | jump_target_vip - 4 180 | } else { 181 | jump_target_vip + 4 182 | }; 183 | 184 | let mut rolling_key = vip; 185 | 186 | let instruction_iter = vm_jump_handler.instructions.iter(); 187 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 188 | !(insn.code() == Code::Lea_r64_m && 189 | insn.memory_displacement64() != 0 && 190 | insn.memory_displacement64() != 191 | 0x100000000) 192 | }); 193 | 194 | let handler_base_address = instruction_iter.next().unwrap().memory_displacement64(); 195 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 196 | !match_fetch_vip(insn, &new_vm_context.register_allocation) 197 | }); 198 | 199 | // Get the reg where the encrypted offset has been loaded into 200 | let encrypted_offset_reg = instruction_iter.next().unwrap().op0_register(); 201 | 202 | let encrypted_offset = fetch_dword_vip(pe_file, pe_bytes, &mut vip, direction_is_forwards); 203 | 204 | let encryption_iter = instruction_iter.take_while(|&insn| { 205 | !(match_push_rolling_key(insn, 206 | &new_vm_context.register_allocation)) 207 | }); 208 | 209 | let unencrypted_offset = encrypted_offset.emulate_encryption(encryption_iter, 210 | &mut rolling_key, 211 | encrypted_offset_reg); 212 | 213 | // hmmm yes 214 | // movsxd offset_reg, offset_reg_32 215 | // add handler_base, offset_reg 216 | let next_handler_address = 217 | handler_base_address.wrapping_add(unencrypted_offset as i32 as i64 as u64); 218 | 219 | let vip_value = vip; 220 | 221 | new_vm_context.vip_direction_forwards = direction_is_forwards; 222 | new_vm_context.rolling_key = rolling_key; 223 | new_vm_context.initial_vip = jump_target_vip; 224 | new_vm_context.vip_value = vip_value; 225 | new_vm_context.handler_address = next_handler_address; 226 | new_vm_context 227 | } 228 | 229 | pub fn disassemble_context(&mut self, 230 | pe_file: &PeFile, 231 | pe_bytes: &[u8]) 232 | -> Vec<(u64, HandlerVmInstruction, u64)> { 233 | let mut handlers = Vec::new(); 234 | 235 | println!("{:<15} | {:<30} | Handler address", "VIP", "Disassembly"); 236 | loop { 237 | let mut halt = false; 238 | let vm_handler = VmHandler::new(self.handler_address, pe_file, pe_bytes); 239 | 240 | let handler_class = vm_handler.match_handler_class(&self.register_allocation); 241 | let handler_address = self.handler_address; 242 | 243 | let handler_instruction; 244 | 245 | let vip = self.vip_value; 246 | 247 | match handler_class { 248 | HandlerClass::UnconditionalBranch => { 249 | handler_instruction = vm_handler.match_branch_instructions(self); 250 | 251 | halt = true; 252 | }, 253 | HandlerClass::NoVipChange => { 254 | handler_instruction = vm_handler.match_no_vip_change_instructions(self); 255 | halt = true; 256 | }, 257 | HandlerClass::ByteOperand => { 258 | //println!("Disassembled single byte operand"); 259 | let byte_operand = 260 | self.disassemble_single_byte_operand(&vm_handler, pe_file, pe_bytes); 261 | handler_instruction = 262 | vm_handler.match_byte_operand_instructions(&self.register_allocation, 263 | byte_operand); 264 | }, 265 | HandlerClass::WordOperand => { 266 | //println!("Disassembled single word operand"); 267 | let word_operand = 268 | self.disassemble_single_word_operand(&vm_handler, pe_file, pe_bytes); 269 | handler_instruction = 270 | vm_handler.match_word_operand_instructions(&self.register_allocation, 271 | word_operand); 272 | }, 273 | HandlerClass::DwordOperand => { 274 | //println!("Disassembled single dword operand"); 275 | let dword_operand = 276 | self.disassemble_single_dword_operand(&vm_handler, pe_file, pe_bytes); 277 | handler_instruction = 278 | vm_handler.match_dword_operand_instructions(&self.register_allocation, 279 | dword_operand); 280 | }, 281 | HandlerClass::QwordOperand => { 282 | //println!("Disassembled single qword operand"); 283 | let qword_operand = 284 | self.disassemble_single_qword_operand(&vm_handler, pe_file, pe_bytes); 285 | handler_instruction = 286 | vm_handler.match_qword_operand_instructions(&self.register_allocation, 287 | qword_operand); 288 | }, 289 | HandlerClass::NoOperand => { 290 | //println!("Disassembled no operand"); 291 | self.disassemble_no_operand(&vm_handler, pe_file, pe_bytes); 292 | handler_instruction = 293 | vm_handler.match_no_operand_instructions(self, &self.register_allocation); 294 | match handler_instruction { 295 | HandlerVmInstruction::JumpDecVspXchng | 296 | HandlerVmInstruction::JumpIncVspXchng | 297 | HandlerVmInstruction::JumpDecVspChange | 298 | HandlerVmInstruction::JumpIncVspChange | 299 | HandlerVmInstruction::JumpDec | 300 | HandlerVmInstruction::JumpInc | 301 | HandlerVmInstruction::Nop => { 302 | halt = true; 303 | }, 304 | 305 | _ => {}, 306 | } 307 | }, 308 | } 309 | handlers.push((vip, handler_instruction, handler_address)); 310 | // This shit don't work if I combine them so fuck it 311 | println!("{:<15} | {:<30} | {:#x}", 312 | format!("{:#x}", vip), 313 | format!("{}", handler_instruction), 314 | handler_address); 315 | 316 | if halt { 317 | break; 318 | } 319 | } 320 | 321 | handlers 322 | } 323 | pub fn disassemble_single_dword_operand(&mut self, 324 | vm_handler: &VmHandler, 325 | pe_file: &PeFile, 326 | pe_bytes: &[u8]) 327 | -> u32 { 328 | let instruction_iter = vm_handler.instructions.iter(); 329 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 330 | !match_xor_32_rolling_key_source(insn, 331 | &self.register_allocation) 332 | }); 333 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 334 | 335 | let encryption_iter = instruction_iter.take_while(|insn| { 336 | !match_push_rolling_key(insn, 337 | &self.register_allocation) 338 | }); 339 | 340 | let encrypted_dword = fetch_dword_vip(pe_file, 341 | pe_bytes, 342 | &mut self.vip_value, 343 | self.vip_direction_forwards); 344 | 345 | let return_dword = encrypted_dword.emulate_encryption(encryption_iter, 346 | &mut self.rolling_key, 347 | encrypted_reg); 348 | 349 | let encrypted_offset = fetch_dword_vip(pe_file, 350 | pe_bytes, 351 | &mut self.vip_value, 352 | self.vip_direction_forwards); 353 | 354 | let instruction_iter = vm_handler.instructions.iter(); 355 | // Skip it once because dword arg 356 | let mut match_count = 0; 357 | let instruction_iter = 358 | instruction_iter.skip_while(|insn| { 359 | if match_fetch_vip(insn, &self.register_allocation) { 360 | match_count += 1; 361 | } 362 | 363 | match_count != 2 364 | }); 365 | 366 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 367 | !match_xor_32_rolling_key_source(insn, 368 | &self.register_allocation) 369 | }); 370 | 371 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 372 | let encryption_iter = instruction_iter.take_while(|insn| { 373 | !match_push_rolling_key(insn, 374 | &self.register_allocation) 375 | }); 376 | 377 | let unencrypted_offset = encrypted_offset.emulate_encryption(encryption_iter, 378 | &mut self.rolling_key, 379 | encrypted_reg); 380 | 381 | // hmmm yes 382 | // movsxd offset_reg, offset_reg_32 383 | // add handler_base, offset_reg 384 | let next_handler_address = self.handler_address 385 | .wrapping_add(unencrypted_offset as i32 as i64 as u64); 386 | 387 | self.handler_address = next_handler_address; 388 | 389 | return_dword 390 | } 391 | 392 | pub fn disassemble_single_qword_operand(&mut self, 393 | vm_handler: &VmHandler, 394 | pe_file: &PeFile, 395 | pe_bytes: &[u8]) 396 | -> u64 { 397 | let instruction_iter = vm_handler.instructions.iter(); 398 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 399 | !match_xor_64_rolling_key_source(insn, 400 | &self.register_allocation) 401 | }); 402 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 403 | 404 | let encryption_iter = instruction_iter.take_while(|insn| { 405 | !match_xor_64_rolling_key_dest(insn, &self.register_allocation) 406 | }); 407 | let encrypted_qword = fetch_qword_vip(pe_file, 408 | pe_bytes, 409 | &mut self.vip_value, 410 | self.vip_direction_forwards); 411 | 412 | let return_qword = encrypted_qword.emulate_encryption(encryption_iter, 413 | &mut self.rolling_key, 414 | encrypted_reg); 415 | 416 | let encrypted_offset = fetch_dword_vip(pe_file, 417 | pe_bytes, 418 | &mut self.vip_value, 419 | self.vip_direction_forwards); 420 | 421 | let instruction_iter = vm_handler.instructions.iter(); 422 | 423 | let instruction_iter = 424 | instruction_iter.skip_while(|insn| !match_fetch_vip(insn, &self.register_allocation)); 425 | 426 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 427 | !match_xor_32_rolling_key_source(insn, 428 | &self.register_allocation) 429 | }); 430 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 431 | let encryption_iter = instruction_iter.take_while(|insn| { 432 | !match_push_rolling_key(insn, 433 | &self.register_allocation) 434 | }); 435 | 436 | let unencrypted_offset = encrypted_offset.emulate_encryption(encryption_iter, 437 | &mut self.rolling_key, 438 | encrypted_reg); 439 | 440 | // hmmm yes 441 | // movsxd offset_reg, offset_reg_32 442 | // add handler_base, offset_reg 443 | let next_handler_address = self.handler_address 444 | .wrapping_add(unencrypted_offset as i32 as i64 as u64); 445 | 446 | self.handler_address = next_handler_address; 447 | 448 | return_qword 449 | } 450 | 451 | pub fn disassemble_single_word_operand(&mut self, 452 | vm_handler: &VmHandler, 453 | pe_file: &PeFile, 454 | pe_bytes: &[u8]) 455 | -> u16 { 456 | let instruction_iter = vm_handler.instructions.iter(); 457 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 458 | !match_xor_16_rolling_key_source(insn, 459 | &self.register_allocation) 460 | }); 461 | 462 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 463 | 464 | let encryption_iter = instruction_iter.take_while(|insn| { 465 | !match_xor_16_rolling_key_dest(insn, &self.register_allocation) 466 | }); 467 | let encrypted_word = fetch_word_vip(pe_file, 468 | pe_bytes, 469 | &mut self.vip_value, 470 | self.vip_direction_forwards); 471 | 472 | let return_word = encrypted_word.emulate_encryption(encryption_iter, 473 | &mut self.rolling_key, 474 | encrypted_reg); 475 | 476 | let encrypted_offset = fetch_dword_vip(pe_file, 477 | pe_bytes, 478 | &mut self.vip_value, 479 | self.vip_direction_forwards); 480 | 481 | let instruction_iter = vm_handler.instructions.iter(); 482 | 483 | let instruction_iter = 484 | instruction_iter.skip_while(|insn| !match_fetch_vip(insn, &self.register_allocation)); 485 | 486 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 487 | !match_xor_32_rolling_key_source(insn, 488 | &self.register_allocation) 489 | }); 490 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 491 | let encryption_iter = instruction_iter.take_while(|insn| { 492 | !match_push_rolling_key(insn, 493 | &self.register_allocation) 494 | }); 495 | 496 | let unencrypted_offset = encrypted_offset.emulate_encryption(encryption_iter, 497 | &mut self.rolling_key, 498 | encrypted_reg); 499 | 500 | // hmmm yes 501 | // movsxd offset_reg, offset_reg_32 502 | // add handler_base, offset_reg 503 | let next_handler_address = self.handler_address 504 | .wrapping_add(unencrypted_offset as i32 as i64 as u64); 505 | 506 | self.handler_address = next_handler_address; 507 | 508 | return_word 509 | } 510 | 511 | pub fn disassemble_single_byte_operand(&mut self, 512 | vm_handler: &VmHandler, 513 | pe_file: &PeFile, 514 | pe_bytes: &[u8]) 515 | -> u8 { 516 | let instruction_iter = vm_handler.instructions.iter(); 517 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 518 | !match_xor_8_rolling_key_source(insn, 519 | &self.register_allocation) 520 | }); 521 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 522 | 523 | let encryption_iter = instruction_iter.take_while(|insn| { 524 | !match_xor_8_rolling_key_dest(insn, &self.register_allocation) 525 | }); 526 | let encrypted_byte = fetch_byte_vip(pe_file, 527 | pe_bytes, 528 | &mut self.vip_value, 529 | self.vip_direction_forwards); 530 | 531 | let return_byte = encrypted_byte.emulate_encryption(encryption_iter, 532 | &mut self.rolling_key, 533 | encrypted_reg); 534 | 535 | let encrypted_offset = fetch_dword_vip(pe_file, 536 | pe_bytes, 537 | &mut self.vip_value, 538 | self.vip_direction_forwards); 539 | 540 | let instruction_iter = vm_handler.instructions.iter(); 541 | 542 | let instruction_iter = 543 | instruction_iter.skip_while(|insn| !match_fetch_vip(insn, &self.register_allocation)); 544 | 545 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 546 | !match_xor_32_rolling_key_source(insn, 547 | &self.register_allocation) 548 | }); 549 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 550 | let encryption_iter = instruction_iter.take_while(|insn| { 551 | !match_push_rolling_key(insn, 552 | &self.register_allocation) 553 | }); 554 | 555 | let unencrypted_offset = encrypted_offset.emulate_encryption(encryption_iter, 556 | &mut self.rolling_key, 557 | encrypted_reg); 558 | 559 | // hmmm yes 560 | // movsxd offset_reg, offset_reg_32 561 | // add handler_base, offset_reg 562 | let next_handler_address = self.handler_address 563 | .wrapping_add(unencrypted_offset as i32 as i64 as u64); 564 | 565 | self.handler_address = next_handler_address; 566 | 567 | return_byte 568 | } 569 | 570 | pub fn disassemble_no_operand(&mut self, 571 | vm_handler: &VmHandler, 572 | pe_file: &PeFile, 573 | pe_bytes: &[u8]) { 574 | let encrypted_offset = fetch_dword_vip(pe_file, 575 | pe_bytes, 576 | &mut self.vip_value, 577 | self.vip_direction_forwards); 578 | 579 | let instruction_iter = vm_handler.instructions.iter(); 580 | 581 | let instruction_iter = 582 | instruction_iter.skip_while(|insn| !match_fetch_vip(insn, &self.register_allocation)); 583 | 584 | let mut instruction_iter = instruction_iter.skip_while(|insn| { 585 | !match_xor_32_rolling_key_source(insn, 586 | &self.register_allocation) 587 | }); 588 | let encrypted_reg = instruction_iter.next().unwrap().op0_register(); 589 | let encryption_iter = instruction_iter.take_while(|insn| { 590 | !match_push_rolling_key(insn, 591 | &self.register_allocation) 592 | }); 593 | 594 | let unencrypted_offset = encrypted_offset.emulate_encryption(encryption_iter, 595 | &mut self.rolling_key, 596 | encrypted_reg); 597 | 598 | // hmmm yes 599 | // movsxd offset_reg, offset_reg_32 600 | // add handler_base, offset_reg 601 | let next_handler_address = self.handler_address 602 | .wrapping_add(unencrypted_offset as i32 as i64 as u64); 603 | 604 | self.handler_address = next_handler_address; 605 | } 606 | } 607 | 608 | pub struct VmHandler { 609 | pub instructions: Vec, 610 | } 611 | 612 | impl VmHandler { 613 | pub fn new(address: u64, 614 | pe_file: &PeFile, 615 | pe_bytes: &[u8]) 616 | -> Self { 617 | let mut instruction_address = address; 618 | let mut instructions = Vec::new(); 619 | 620 | loop { 621 | let instruction = disassemble_instruction_at_va(pe_file, pe_bytes, instruction_address); 622 | 623 | match instruction.code() { 624 | Code::Retnq | Code::Jmp_rm64 => { 625 | instructions.push(instruction); 626 | break; 627 | }, 628 | Code::Jmp_rel32_64 => { 629 | let jmp_target = instruction.near_branch64(); 630 | instruction_address = jmp_target; 631 | }, 632 | 633 | _ => { 634 | instruction_address += instruction.len() as u64; 635 | instructions.push(instruction); 636 | }, 637 | } 638 | } 639 | 640 | Self { instructions } 641 | } 642 | 643 | pub fn get_register_allocation_vm_entry(&self) -> VmRegisterAllocation { 644 | // Find the handler_address register 645 | let handler_address_reg = { 646 | let instruction_last = self.instructions.last().unwrap(); 647 | if instruction_last.code() == Code::Jmp_rm64 { 648 | instruction_last.op0_register().into() 649 | } else { 650 | let instruction = self.instructions 651 | .iter() 652 | .rev() 653 | .find(|&&insn| insn.code() == Code::Push_r64) 654 | .unwrap(); 655 | instruction.op0_register().into() 656 | } 657 | }; 658 | 659 | // Find key register 660 | let pop_instruction = self.instructions 661 | .iter() 662 | .rev() 663 | .find(|&&insn| insn.code() == Code::Pop_r64) 664 | .unwrap(); 665 | 666 | let key = pop_instruction.op0_register().into(); 667 | 668 | // Find vsp register 669 | let mov_vsp_instruction = self.instructions 670 | .iter() 671 | .find(|&&insn| { 672 | insn.code() == Code::Mov_r64_rm64 && 673 | insn.op1_register() == iced_x86::Register::RSP 674 | }) 675 | .unwrap(); 676 | let vsp = mov_vsp_instruction.op0_register().into(); 677 | 678 | // Find vip register 679 | let mov_vip_instruction = self.instructions 680 | .iter() 681 | .find(|&&insn| { 682 | insn.code() == Code::Mov_r64_rm64 && 683 | insn.op1_kind() == OpKind::Memory && 684 | insn.memory_displacement64() == 0x90 685 | }) 686 | .unwrap(); 687 | let vip = mov_vip_instruction.op0_register().into(); 688 | 689 | VmRegisterAllocation { vip, 690 | vsp, 691 | key, 692 | handler_address: handler_address_reg } 693 | } 694 | 695 | pub fn get_register_allocation_vm_jump_xchng(&self, 696 | old_register_allocation: &mut VmRegisterAllocation) 697 | { 698 | let mut instruction_iter = self.instructions.iter(); 699 | let mov_to_vip = 700 | instruction_iter.find(|insn| { 701 | match_fetch_reg_any_size(insn, old_register_allocation.vsp.into()).is_some() 702 | }); 703 | 704 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 705 | 706 | let _add_vsp_instruction = 707 | instruction_iter.find(|insn| { 708 | match_add_vsp_get_amount(insn, old_register_allocation).is_some() 709 | }); 710 | 711 | let xchng = instruction_iter.find(|insn| match_xchng_reg(insn, new_vip)); 712 | 713 | let new_vsp_value_reg; 714 | let new_vip_reg: Register; 715 | 716 | match xchng { 717 | Some(xchng_insn) => { 718 | if !(xchng_insn.op0_register() == new_vip && 719 | xchng_insn.op1_register() == old_register_allocation.vsp.into()) && 720 | !(xchng_insn.op1_register() == new_vip && 721 | xchng_insn.op0_register() == old_register_allocation.vsp.into()) 722 | { 723 | panic!(); 724 | } else { 725 | new_vsp_value_reg = new_vip; 726 | new_vip_reg = old_register_allocation.vsp.into(); 727 | } 728 | }, 729 | None => panic!(), 730 | } 731 | let mov_new_vsp = 732 | instruction_iter.clone() 733 | .find(|insn| match_mov_reg_source(insn, new_vsp_value_reg)); 734 | 735 | let new_vsp_reg = match mov_new_vsp { 736 | Some(insn) => insn.op0_register().full_register(), 737 | None => new_vsp_value_reg, 738 | }; 739 | 740 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip_reg)); 741 | 742 | let new_key_register = store_key_reg.unwrap().op0_register(); 743 | 744 | old_register_allocation.vsp = new_vsp_reg.into(); 745 | old_register_allocation.vip = new_vip_reg.into(); 746 | old_register_allocation.key = new_key_register.into(); 747 | } 748 | 749 | pub fn get_register_allocation_vm_jump(&self, 750 | changed_vsp: bool, 751 | old_register_allocation: &mut VmRegisterAllocation) { 752 | let mut instruction_iter = self.instructions.iter(); 753 | let mov_to_vip = 754 | instruction_iter.find(|insn| { 755 | match_fetch_reg_any_size(insn, old_register_allocation.vsp.into()).is_some() 756 | }); 757 | 758 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 759 | 760 | let _add_vsp_instruction = 761 | instruction_iter.find(|insn| { 762 | match_add_vsp_get_amount(insn, old_register_allocation).is_some() 763 | }); 764 | 765 | let mut cloned_iter = instruction_iter.clone(); 766 | let mov_vip = cloned_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 767 | let new_vip = match mov_vip { 768 | Some(mov_vip) => { 769 | let potential_vip = mov_vip.op0_register().full_register(); 770 | if cloned_iter.any(|insn| match_sub_reg_left(insn, potential_vip)) { 771 | new_vip 772 | } else { 773 | potential_vip 774 | } 775 | }, 776 | None => new_vip, 777 | }; 778 | if changed_vsp { 779 | let mov_vsp = 780 | instruction_iter.find(|insn| { 781 | match_mov_reg_source(insn, old_register_allocation.vsp.into()) 782 | }); 783 | let new_vsp = mov_vsp.unwrap().op0_register().full_register(); 784 | old_register_allocation.vsp = new_vsp.into(); 785 | } 786 | 787 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 788 | 789 | let new_key_register = store_key_reg.unwrap().op0_register(); 790 | 791 | old_register_allocation.vip = new_vip.into(); 792 | old_register_allocation.key = new_key_register.into(); 793 | } 794 | 795 | pub fn get_push_order_vm_entry(&self) -> Vec { 796 | let mut registers = Vec::new(); 797 | 798 | for instruction in self.instructions 799 | .iter() 800 | .take_while(|&&insn| insn.code() != Code::Mov_r64_imm64) 801 | { 802 | match instruction.code() { 803 | Code::Push_r64 => { 804 | let reg = instruction.op0_register(); 805 | registers.push(reg.into()); 806 | }, 807 | Code::Pushfq => { 808 | registers.push(Registers::Flags); 809 | }, 810 | _ => {}, 811 | } 812 | } 813 | 814 | registers 815 | } 816 | 817 | pub fn determine_is_forwards(&self, 818 | reg_allocation: &VmRegisterAllocation) 819 | -> bool { 820 | for instruction in self.instructions.iter() { 821 | match instruction.code() { 822 | Code::Add_rm64_imm32 => { 823 | if reg_allocation.vip == instruction.op0_register().into() && 824 | instruction.immediate32() == 0x4 825 | { 826 | return true; 827 | } 828 | }, 829 | Code::Sub_rm64_imm32 => { 830 | if reg_allocation.vip == instruction.op0_register().into() && 831 | instruction.immediate32() == 0x4 832 | { 833 | return false; 834 | } 835 | }, 836 | _ => continue, 837 | } 838 | } 839 | panic!("Direction of vm_entry not found") 840 | } 841 | 842 | pub fn get_initial_vip(&self, 843 | reg_allocation: &VmRegisterAllocation, 844 | pushed_val: u64) 845 | -> u64 { 846 | let mut encrypted_vip = pushed_val as u32; 847 | for instruction in 848 | self.instructions 849 | .iter() 850 | .skip_while(|&insn| !match_fetch_encrypted_vip(insn, reg_allocation)) 851 | .take_while(|&insn| { 852 | !((insn.code() == Code::Lea_r64_m || insn.code() == Code::Add_r64_rm64) && 853 | check_full_reg_written(insn, reg_allocation.vip.into())) 854 | }) 855 | .filter(|&insn| check_full_reg_written(insn, reg_allocation.vip.into())) 856 | { 857 | let transform = get_transform_for_instruction(instruction); 858 | 859 | if let Some(transform) = transform { 860 | encrypted_vip = encrypted_vip.emulate_transform(transform); 861 | } 862 | } 863 | 864 | encrypted_vip as u64 865 | } 866 | } 867 | 868 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 869 | pub enum Registers { 870 | Rax, 871 | Rbx, 872 | Rcx, 873 | Rdx, 874 | Rsi, 875 | Rdi, 876 | Rsp, 877 | Rbp, 878 | R8, 879 | R9, 880 | R10, 881 | R11, 882 | R12, 883 | R13, 884 | R14, 885 | R15, 886 | Flags, 887 | } 888 | 889 | impl Registers { 890 | pub fn to_arg_index(self) -> u64 { 891 | match self { 892 | Registers::Rax => 0, 893 | Registers::Rbx => 1, 894 | Registers::Rcx => 2, 895 | Registers::Rdx => 3, 896 | Registers::Rsi => 4, 897 | Registers::Rdi => 5, 898 | Registers::Rsp => 7, 899 | Registers::Rbp => 6, 900 | Registers::R8 => 8, 901 | Registers::R9 => 9, 902 | Registers::R10 => 10, 903 | Registers::R11 => 11, 904 | Registers::R12 => 12, 905 | Registers::R13 => 13, 906 | Registers::R14 => 14, 907 | Registers::R15 => 15, 908 | Registers::Flags => 16, 909 | } 910 | } 911 | } 912 | 913 | impl From for Registers { 914 | fn from(reg: iced_x86::Register) -> Self { 915 | match reg { 916 | iced_x86::Register::RAX => Registers::Rax, 917 | iced_x86::Register::RBX => Registers::Rbx, 918 | iced_x86::Register::RCX => Registers::Rcx, 919 | iced_x86::Register::RDX => Registers::Rdx, 920 | iced_x86::Register::RSI => Registers::Rsi, 921 | iced_x86::Register::RDI => Registers::Rdi, 922 | iced_x86::Register::RSP => Registers::Rsp, 923 | iced_x86::Register::RBP => Registers::Rbp, 924 | iced_x86::Register::R8 => Registers::R8, 925 | iced_x86::Register::R9 => Registers::R9, 926 | iced_x86::Register::R10 => Registers::R10, 927 | iced_x86::Register::R11 => Registers::R11, 928 | iced_x86::Register::R12 => Registers::R12, 929 | iced_x86::Register::R13 => Registers::R13, 930 | iced_x86::Register::R14 => Registers::R14, 931 | iced_x86::Register::R15 => Registers::R15, 932 | 933 | _ => unimplemented!("Register not implemented"), 934 | } 935 | } 936 | } 937 | 938 | impl From for iced_x86::Register { 939 | fn from(reg: Registers) -> iced_x86::Register { 940 | match reg { 941 | Registers::Rax => iced_x86::Register::RAX, 942 | Registers::Rbx => iced_x86::Register::RBX, 943 | Registers::Rcx => iced_x86::Register::RCX, 944 | Registers::Rdx => iced_x86::Register::RDX, 945 | Registers::Rsi => iced_x86::Register::RSI, 946 | Registers::Rdi => iced_x86::Register::RDI, 947 | Registers::Rsp => iced_x86::Register::RSP, 948 | Registers::Rbp => iced_x86::Register::RBP, 949 | Registers::R8 => iced_x86::Register::R8, 950 | Registers::R9 => iced_x86::Register::R9, 951 | Registers::R10 => iced_x86::Register::R10, 952 | Registers::R11 => iced_x86::Register::R11, 953 | Registers::R12 => iced_x86::Register::R12, 954 | Registers::R13 => iced_x86::Register::R13, 955 | Registers::R14 => iced_x86::Register::R14, 956 | Registers::R15 => iced_x86::Register::R15, 957 | _ => unreachable!(), 958 | } 959 | } 960 | } 961 | 962 | pub fn fetch_qword_vip(pe_file: &PeFile, 963 | pe_bytes: &[u8], 964 | vip: &mut u64, 965 | direction_is_forwards: bool) 966 | -> u64 { 967 | let return_value; 968 | 969 | if direction_is_forwards { 970 | return_value = u64::from_le_bytes(read_bytes_at_va(pe_file, pe_bytes, *vip, 8).unwrap() 971 | .try_into() 972 | .unwrap()); 973 | *vip += 8; 974 | } else { 975 | *vip -= 8; 976 | return_value = u64::from_le_bytes(read_bytes_at_va(pe_file, pe_bytes, *vip, 8).unwrap() 977 | .try_into() 978 | .unwrap()); 979 | } 980 | 981 | return_value 982 | } 983 | 984 | pub fn fetch_word_vip(pe_file: &PeFile, 985 | pe_bytes: &[u8], 986 | vip: &mut u64, 987 | direction_is_forwards: bool) 988 | -> u16 { 989 | let return_value; 990 | 991 | if direction_is_forwards { 992 | return_value = u16::from_le_bytes(read_bytes_at_va(pe_file, pe_bytes, *vip, 2).unwrap() 993 | .try_into() 994 | .unwrap()); 995 | *vip += 2; 996 | } else { 997 | *vip -= 2; 998 | return_value = u16::from_le_bytes(read_bytes_at_va(pe_file, pe_bytes, *vip, 2).unwrap() 999 | .try_into() 1000 | .unwrap()); 1001 | } 1002 | 1003 | return_value 1004 | } 1005 | 1006 | pub fn fetch_dword_vip(pe_file: &PeFile, 1007 | pe_bytes: &[u8], 1008 | vip: &mut u64, 1009 | direction_is_forwards: bool) 1010 | -> u32 { 1011 | let return_value; 1012 | 1013 | if direction_is_forwards { 1014 | return_value = u32::from_le_bytes(read_bytes_at_va(pe_file, pe_bytes, *vip, 4).unwrap() 1015 | .try_into() 1016 | .unwrap()); 1017 | *vip += 4; 1018 | } else { 1019 | *vip -= 4; 1020 | return_value = u32::from_le_bytes(read_bytes_at_va(pe_file, pe_bytes, *vip, 4).unwrap() 1021 | .try_into() 1022 | .unwrap()); 1023 | } 1024 | 1025 | return_value 1026 | } 1027 | 1028 | pub fn fetch_byte_vip(pe_file: &PeFile, 1029 | pe_bytes: &[u8], 1030 | vip: &mut u64, 1031 | direction_is_forwards: bool) 1032 | -> u8 { 1033 | let return_value; 1034 | 1035 | if direction_is_forwards { 1036 | return_value = read_bytes_at_va(pe_file, pe_bytes, *vip, 1).unwrap()[0]; 1037 | *vip += 1; 1038 | } else { 1039 | *vip -= 1; 1040 | return_value = read_bytes_at_va(pe_file, pe_bytes, *vip, 1).unwrap()[0]; 1041 | } 1042 | 1043 | return_value 1044 | } 1045 | -------------------------------------------------------------------------------- /src/vm_matchers.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use iced_x86::{Code, Instruction, Register}; 4 | 5 | use crate::{ 6 | match_assembly::*, 7 | util::check_full_reg_written, 8 | vm_handler::{Registers, VmContext, VmHandler, VmRegisterAllocation}, 9 | }; 10 | 11 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 12 | pub enum HandlerClass { 13 | ByteOperand, 14 | WordOperand, 15 | DwordOperand, 16 | QwordOperand, 17 | NoOperand, 18 | UnconditionalBranch, 19 | NoVipChange, 20 | } 21 | 22 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 23 | pub enum HandlerVmInstruction { 24 | /// Size in bytes and reg offset in register file 25 | Pop(usize, u8), 26 | Push(usize, u8), 27 | PushImm64(u64), 28 | PushImm32(u32), 29 | PushImm16(u16), 30 | PushImm8(u8), 31 | PushVsp(usize), 32 | PopVsp(usize), 33 | Add(usize), 34 | Mul(usize), 35 | Imul(usize), 36 | Shr(usize), 37 | Shl(usize), 38 | Shrd(usize), 39 | Shld(usize), 40 | Nand(usize), 41 | Nor(usize), 42 | Fetch(usize), 43 | Store(usize), 44 | PushCr0, 45 | PushCr3, 46 | Rdtsc, 47 | Nop, 48 | VmExit, 49 | JumpDecVspChange, 50 | JumpIncVspChange, 51 | JumpDecVspXchng, 52 | JumpIncVspXchng, 53 | JumpDec, 54 | JumpInc, 55 | UnknownByteOperand, 56 | UnknownWordOperand, 57 | UnknownDwordOperand, 58 | UnknownQwordOperand, 59 | UnknownNoOperand, 60 | UnknownNoVipChange, 61 | Unknown, 62 | } 63 | 64 | impl Display for HandlerVmInstruction { 65 | fn fmt(&self, 66 | f: &mut std::fmt::Formatter<'_>) 67 | -> std::fmt::Result { 68 | /// Local function for fomatting registers 69 | fn format_reg_offset(reg_offset: u8, 70 | size: usize) 71 | -> String { 72 | let register_number = reg_offset / 8; 73 | let inner_reg_offset = reg_offset % 8; 74 | 75 | match size { 76 | 8 => { 77 | format!("r{}", register_number) 78 | }, 79 | 4 => match inner_reg_offset { 80 | 0 => format!("r{}_dword_0", register_number), 81 | 4 => format!("r{}_dword_1", register_number), 82 | _ => unimplemented!(), 83 | }, 84 | 2 => match inner_reg_offset { 85 | 0 => format!("r{}_word_0", register_number), 86 | 2 => format!("r{}_word_1", register_number), 87 | 4 => format!("r{}_word_2", register_number), 88 | 6 => format!("r{}_word_3", register_number), 89 | _ => { 90 | dbg!(inner_reg_offset); 91 | unimplemented!(); 92 | }, 93 | }, 94 | 1 => match inner_reg_offset { 95 | 0 => format!("r{}_byte_0", register_number), 96 | 1 => format!("r{}_byte_1", register_number), 97 | _ => unimplemented!(), 98 | }, 99 | _ => unimplemented!("Size -> not implemented yet {}", size), 100 | } 101 | } 102 | 103 | match self { 104 | HandlerVmInstruction::Pop(size, reg_offset) => write!(f, 105 | "pop{} {}", 106 | size * 8, 107 | format_reg_offset(*reg_offset, 108 | *size)), 109 | HandlerVmInstruction::Push(size, reg_offset) => write!(f, 110 | "push{} {}", 111 | size * 8, 112 | format_reg_offset(*reg_offset, 113 | *size)), 114 | HandlerVmInstruction::PushImm64(imm64) => write!(f, "push_imm64 {:#x}", imm64), 115 | HandlerVmInstruction::PushImm32(imm32) => write!(f, "push_imm32 {:#x}", imm32), 116 | HandlerVmInstruction::PushImm16(imm16) => write!(f, "push_imm16 {:#x}", imm16), 117 | HandlerVmInstruction::PushImm8(imm8) => write!(f, "push_imm8 {:#x}", imm8), 118 | HandlerVmInstruction::PushVsp(size) => write!(f, "pushvsp{}", size * 8), 119 | HandlerVmInstruction::PopVsp(size) => write!(f, "popvsp{}", size * 8), 120 | HandlerVmInstruction::Add(size) => write!(f, "add{}", size * 8), 121 | HandlerVmInstruction::Mul(size) => write!(f, "mul{}", size * 8), 122 | HandlerVmInstruction::Imul(size) => write!(f, "imul{}", size * 8), 123 | HandlerVmInstruction::Shrd(size) => write!(f, "shrd{}", size * 8), 124 | HandlerVmInstruction::Shld(size) => write!(f, "shld{}", size * 8), 125 | HandlerVmInstruction::Shr(size) => write!(f, "shr{}", size * 8), 126 | HandlerVmInstruction::Shl(size) => write!(f, "shl{}", size * 8), 127 | HandlerVmInstruction::Nand(size) => write!(f, "nand{}", size * 8), 128 | HandlerVmInstruction::Nor(size) => write!(f, "nor{}", size * 8), 129 | HandlerVmInstruction::Fetch(size) => write!(f, "fetch{}", size * 8), 130 | HandlerVmInstruction::Store(size) => write!(f, "store{}", size * 8), 131 | HandlerVmInstruction::PushCr0 => write!(f, "push_cr0"), 132 | HandlerVmInstruction::PushCr3 => write!(f, "push_cr3"), 133 | HandlerVmInstruction::Rdtsc => write!(f, "rdtsc"), 134 | HandlerVmInstruction::Nop => write!(f, "nop"), 135 | HandlerVmInstruction::VmExit => write!(f, "vm_exit"), 136 | HandlerVmInstruction::JumpDecVspXchng => write!(f, "jump_dec_vsp_xchng"), 137 | HandlerVmInstruction::JumpIncVspXchng => write!(f, "jump_inc_vsp_xchng"), 138 | HandlerVmInstruction::JumpDecVspChange => write!(f, "jump_dec_vsp_change"), 139 | HandlerVmInstruction::JumpIncVspChange => write!(f, "jump_inc_vsp_change"), 140 | HandlerVmInstruction::JumpDec => write!(f, "jump_dec"), 141 | HandlerVmInstruction::JumpInc => write!(f, "jump_inc"), 142 | HandlerVmInstruction::UnknownByteOperand => { 143 | write!(f, "[unknown byte operand instruction]") 144 | }, 145 | HandlerVmInstruction::UnknownWordOperand => { 146 | write!(f, "[unknown word operand instruction]") 147 | }, 148 | HandlerVmInstruction::UnknownDwordOperand => { 149 | write!(f, "[unknown dword operand instruction]") 150 | }, 151 | HandlerVmInstruction::UnknownQwordOperand => { 152 | write!(f, "[unknown qword operand instruction]") 153 | }, 154 | HandlerVmInstruction::UnknownNoOperand => write!(f, "[unknown no operand instruction]"), 155 | HandlerVmInstruction::UnknownNoVipChange => { 156 | write!(f, "[unknown no vip change instruction]") 157 | }, 158 | HandlerVmInstruction::Unknown => write!(f, "[unknown instruction]"), 159 | } 160 | } 161 | } 162 | 163 | impl VmHandler { 164 | /// Classify the handler based on the class of access to the vip register 165 | pub fn match_handler_class(&self, 166 | reg_allocation: &VmRegisterAllocation) 167 | -> HandlerClass { 168 | // Create an iterator over the instructions of the handler 169 | let instruction_iter = self.instructions.iter(); 170 | 171 | // Collect all the mov accesses to the vip register 172 | let vip_modification_vec = 173 | instruction_iter.clone() 174 | .filter(|insn| check_full_reg_written(insn, reg_allocation.vip.into())) 175 | .filter(|insn| insn.code() == Code::Mov_r64_rm64) 176 | .collect::>(); 177 | 178 | // These registers are used in the stack relocation code of some handlers so 179 | // they are special 180 | if (reg_allocation.vip != Registers::Rsi && 181 | reg_allocation.vip != Registers::Rdi && 182 | !vip_modification_vec.is_empty()) || 183 | (vip_modification_vec.len() >= 2) 184 | { 185 | return HandlerClass::UnconditionalBranch; 186 | } 187 | 188 | // Collect all instructions that advance the vip and get their immediate values 189 | let vip_update_vec = 190 | instruction_iter.filter(|insn| check_full_reg_written(insn, reg_allocation.vip.into())) 191 | .filter(|insn| { 192 | insn.code() == Code::Add_rm64_imm32 || 193 | insn.code() == Code::Sub_rm64_imm32 194 | }) 195 | .map(|insn| insn.immediate32()) 196 | .collect::>(); 197 | 198 | // Match the vip offsets to a handler class 199 | match vip_update_vec.as_slice() { 200 | &[] => HandlerClass::NoVipChange, 201 | &[4] => HandlerClass::NoOperand, 202 | &[8, 4] => HandlerClass::QwordOperand, 203 | &[4, 4] => HandlerClass::DwordOperand, 204 | &[2, 4] => HandlerClass::WordOperand, 205 | &[1, 4] => HandlerClass::ByteOperand, 206 | slice => { 207 | panic!("Unimplemented handler class with slice {:?}", slice) 208 | }, 209 | } 210 | } 211 | 212 | /// Function for matching handlers of the UnconditionalBranch class 213 | pub fn match_branch_instructions(&self, 214 | vm_context: &VmContext) 215 | -> HandlerVmInstruction { 216 | if vm_match_vm_exit(self, &vm_context.register_allocation) { 217 | return HandlerVmInstruction::VmExit; 218 | } 219 | 220 | if vm_match_jmp_dec_vsp_change(self, vm_context) { 221 | return HandlerVmInstruction::JumpDecVspChange; 222 | } 223 | 224 | if vm_match_jmp_inc_vsp_change(self, vm_context) { 225 | return HandlerVmInstruction::JumpIncVspChange; 226 | } 227 | 228 | if vm_match_jmp_dec_vsp_xchng(self, vm_context) { 229 | return HandlerVmInstruction::JumpDecVspXchng; 230 | } 231 | 232 | if vm_match_jmp_inc_vsp_xchng(self, vm_context) { 233 | return HandlerVmInstruction::JumpIncVspXchng; 234 | } 235 | 236 | if vm_match_jmp_dec(self, vm_context) { 237 | return HandlerVmInstruction::JumpDec; 238 | } 239 | 240 | if vm_match_jmp_inc(self, vm_context) { 241 | return HandlerVmInstruction::JumpInc; 242 | } 243 | 244 | HandlerVmInstruction::Unknown 245 | } 246 | 247 | /// Function for mathing the handlers of the NoVipChange class 248 | pub fn match_no_vip_change_instructions(&self, 249 | vm_context: &VmContext) 250 | -> HandlerVmInstruction { 251 | if vm_match_vm_exit(self, &vm_context.register_allocation) { 252 | return HandlerVmInstruction::VmExit; 253 | } 254 | 255 | if vm_match_jmp_dec_vsp_change(self, vm_context) { 256 | return HandlerVmInstruction::JumpDecVspChange; 257 | } 258 | 259 | if vm_match_jmp_inc_vsp_change(self, vm_context) { 260 | return HandlerVmInstruction::JumpIncVspChange; 261 | } 262 | 263 | if vm_match_jmp_dec_vsp_xchng(self, vm_context) { 264 | return HandlerVmInstruction::JumpDecVspXchng; 265 | } 266 | 267 | if vm_match_jmp_inc_vsp_xchng(self, vm_context) { 268 | return HandlerVmInstruction::JumpIncVspXchng; 269 | } 270 | 271 | if vm_match_jmp_dec(self, vm_context) { 272 | return HandlerVmInstruction::JumpDec; 273 | } 274 | 275 | if vm_match_jmp_inc(self, vm_context) { 276 | return HandlerVmInstruction::JumpInc; 277 | } 278 | 279 | HandlerVmInstruction::UnknownNoVipChange 280 | } 281 | 282 | /// Function for mathing the handlers of the ByteOperand class 283 | pub fn match_byte_operand_instructions(&self, 284 | reg_allocation: &VmRegisterAllocation, 285 | byte_operand: u8) 286 | -> HandlerVmInstruction { 287 | if vm_match_push_imm8(self, reg_allocation) { 288 | return HandlerVmInstruction::PushImm8(byte_operand); 289 | } 290 | 291 | if let Some(size) = vm_match_vm_reg_pop(self, reg_allocation) { 292 | return HandlerVmInstruction::Pop(size, byte_operand); 293 | } 294 | 295 | if let Some(size) = vm_match_vm_reg_pop_v2(self, reg_allocation) { 296 | return HandlerVmInstruction::Pop(size, byte_operand); 297 | } 298 | 299 | if let Some(size) = vm_match_vm_reg_push(self, reg_allocation) { 300 | return HandlerVmInstruction::Push(size, byte_operand); 301 | } 302 | 303 | HandlerVmInstruction::UnknownByteOperand 304 | } 305 | 306 | /// Function for mathing the handlers of the WordOperand class 307 | pub fn match_word_operand_instructions(&self, 308 | reg_allocation: &VmRegisterAllocation, 309 | word_operand: u16) 310 | -> HandlerVmInstruction { 311 | if vm_match_push_imm16(self, reg_allocation) { 312 | return HandlerVmInstruction::PushImm16(word_operand); 313 | } 314 | HandlerVmInstruction::UnknownWordOperand 315 | } 316 | 317 | /// Function for mathing the handlers of the DwordOperand class 318 | pub fn match_dword_operand_instructions(&self, 319 | reg_allocation: &VmRegisterAllocation, 320 | dword_operand: u32) 321 | -> HandlerVmInstruction { 322 | if vm_match_push_imm32(self, reg_allocation) { 323 | return HandlerVmInstruction::PushImm32(dword_operand); 324 | } 325 | HandlerVmInstruction::UnknownDwordOperand 326 | } 327 | 328 | /// Function for mathing the handlers of the QwordOperand class 329 | pub fn match_qword_operand_instructions(&self, 330 | reg_allocation: &VmRegisterAllocation, 331 | qword_operand: u64) 332 | -> HandlerVmInstruction { 333 | if vm_match_push_imm64(self, reg_allocation) { 334 | return HandlerVmInstruction::PushImm64(qword_operand); 335 | } 336 | HandlerVmInstruction::UnknownQwordOperand 337 | } 338 | 339 | /// Function for mathing the handlers of the NoOperand class 340 | pub fn match_no_operand_instructions(&self, 341 | vm_context: &VmContext, 342 | reg_allocation: &VmRegisterAllocation) 343 | -> HandlerVmInstruction { 344 | if vm_match_nop(self) { 345 | return HandlerVmInstruction::Nop; 346 | } 347 | 348 | if vm_match_push_cr0(self) { 349 | return HandlerVmInstruction::PushCr0; 350 | } 351 | 352 | if vm_match_push_cr3(self) { 353 | return HandlerVmInstruction::PushCr3; 354 | } 355 | 356 | if vm_match_rdtsc(self) { 357 | return HandlerVmInstruction::Rdtsc; 358 | } 359 | 360 | if let Some(size) = vm_match_push_vsp(self, reg_allocation) { 361 | return HandlerVmInstruction::PushVsp(size); 362 | } 363 | 364 | if vm_match_jmp_dec_vsp_change(self, vm_context) { 365 | return HandlerVmInstruction::JumpDecVspChange; 366 | } 367 | 368 | if vm_match_jmp_inc_vsp_change(self, vm_context) { 369 | return HandlerVmInstruction::JumpIncVspChange; 370 | } 371 | 372 | if vm_match_jmp_dec_vsp_xchng(self, vm_context) { 373 | return HandlerVmInstruction::JumpDecVspXchng; 374 | } 375 | 376 | if vm_match_jmp_inc_vsp_xchng(self, vm_context) { 377 | return HandlerVmInstruction::JumpIncVspXchng; 378 | } 379 | 380 | if vm_match_jmp_dec(self, vm_context) { 381 | return HandlerVmInstruction::JumpDec; 382 | } 383 | 384 | if vm_match_jmp_inc(self, vm_context) { 385 | return HandlerVmInstruction::JumpInc; 386 | } 387 | 388 | if let Some(size) = vm_match_add(self, reg_allocation) { 389 | return HandlerVmInstruction::Add(size); 390 | } 391 | 392 | if let Some(size) = vm_match_add_byte(self, reg_allocation) { 393 | return HandlerVmInstruction::Add(size); 394 | } 395 | 396 | if let Some(size) = vm_match_mul(self, reg_allocation) { 397 | return HandlerVmInstruction::Mul(size); 398 | } 399 | 400 | if let Some(size) = vm_match_imul(self, reg_allocation) { 401 | return HandlerVmInstruction::Imul(size); 402 | } 403 | 404 | if let Some(size) = vm_match_nand(self, reg_allocation) { 405 | return HandlerVmInstruction::Nand(size); 406 | } 407 | 408 | if let Some(size) = vm_match_nand_byte(self, reg_allocation) { 409 | return HandlerVmInstruction::Nand(size); 410 | } 411 | 412 | if let Some(size) = vm_match_nor(self, reg_allocation) { 413 | return HandlerVmInstruction::Nor(size); 414 | } 415 | 416 | if let Some(size) = vm_match_nor_byte(self, reg_allocation) { 417 | return HandlerVmInstruction::Nor(size); 418 | } 419 | 420 | if vm_match_pop_vsp_64(self, reg_allocation) { 421 | return HandlerVmInstruction::PopVsp(8); 422 | } 423 | 424 | if let Some(size) = vm_match_fetch(self, reg_allocation) { 425 | return HandlerVmInstruction::Fetch(size); 426 | } 427 | 428 | if let Some(size) = vm_match_fetch_byte(self, reg_allocation) { 429 | return HandlerVmInstruction::Fetch(size); 430 | } 431 | 432 | if let Some(size) = vm_match_store(self, reg_allocation) { 433 | return HandlerVmInstruction::Store(size); 434 | } 435 | 436 | if let Some(size) = vm_match_shr(self, reg_allocation) { 437 | return HandlerVmInstruction::Shr(size); 438 | } 439 | 440 | if let Some(size) = vm_match_shr_byte(self, reg_allocation) { 441 | return HandlerVmInstruction::Shr(size); 442 | } 443 | 444 | if let Some(size) = vm_match_shl(self, reg_allocation) { 445 | return HandlerVmInstruction::Shl(size); 446 | } 447 | 448 | if let Some(size) = vm_match_shl_byte(self, reg_allocation) { 449 | return HandlerVmInstruction::Shl(size); 450 | } 451 | 452 | if let Some(size) = vm_match_shrd(self, reg_allocation) { 453 | return HandlerVmInstruction::Shrd(size); 454 | } 455 | 456 | if let Some(size) = vm_match_shld(self, reg_allocation) { 457 | return HandlerVmInstruction::Shld(size); 458 | } 459 | 460 | HandlerVmInstruction::UnknownNoOperand 461 | } 462 | } 463 | 464 | fn vm_match_jmp_dec(vm_handler: &VmHandler, 465 | vm_context: &VmContext) 466 | -> bool { 467 | let mut instruction_iter = vm_handler.instructions.iter(); 468 | let mov_to_vip = 469 | instruction_iter.find(|insn| { 470 | match_fetch_reg_any_size(insn, vm_context.register_allocation.vsp.into()).is_some() 471 | }); 472 | 473 | if mov_to_vip.is_none() { 474 | return false; 475 | } 476 | 477 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 478 | 479 | let add_vsp_instruction = 480 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, &vm_context.register_allocation).is_some()); 481 | 482 | if add_vsp_instruction.is_none() { 483 | return false; 484 | } 485 | 486 | if add_vsp_instruction.unwrap().immediate32() != 8 { 487 | return false; 488 | } 489 | 490 | let mut cloned_iter = instruction_iter.clone(); 491 | let mov_vip = cloned_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 492 | let new_vip = match mov_vip { 493 | Some(mov_vip) => { 494 | let potential_vip = mov_vip.op0_register().full_register(); 495 | if cloned_iter.any(|insn| match_sub_reg_left(insn, potential_vip)) { 496 | new_vip 497 | } else { 498 | potential_vip 499 | } 500 | }, 501 | None => new_vip, 502 | }; 503 | 504 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 505 | 506 | if store_key_reg.is_none() { 507 | return false; 508 | } 509 | 510 | instruction_iter.any(|insn| match_sub_reg_by_amount(insn, new_vip, 4)) 511 | } 512 | 513 | fn vm_match_jmp_inc(vm_handler: &VmHandler, 514 | vm_context: &VmContext) 515 | -> bool { 516 | let mut instruction_iter = vm_handler.instructions.iter(); 517 | let mov_to_vip = 518 | instruction_iter.find(|insn| { 519 | match_fetch_reg_any_size(insn, vm_context.register_allocation.vsp.into()).is_some() 520 | }); 521 | 522 | if mov_to_vip.is_none() { 523 | return false; 524 | } 525 | 526 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 527 | 528 | let add_vsp_instruction = 529 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, &vm_context.register_allocation).is_some()); 530 | 531 | if add_vsp_instruction.is_none() { 532 | return false; 533 | } 534 | 535 | if add_vsp_instruction.unwrap().immediate32() != 8 { 536 | return false; 537 | } 538 | 539 | let mut cloned_iter = instruction_iter.clone(); 540 | let mov_vip = cloned_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 541 | let new_vip = match mov_vip { 542 | Some(mov_vip) => { 543 | let potential_vip = mov_vip.op0_register().full_register(); 544 | if cloned_iter.any(|insn| match_sub_reg_left(insn, potential_vip)) { 545 | new_vip 546 | } else { 547 | potential_vip 548 | } 549 | }, 550 | None => new_vip, 551 | }; 552 | 553 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 554 | 555 | if store_key_reg.is_none() { 556 | return false; 557 | } 558 | 559 | instruction_iter.any(|insn| match_add_reg_by_amount(insn, new_vip, 4)) 560 | } 561 | 562 | fn vm_match_jmp_dec_vsp_change(vm_handler: &VmHandler, 563 | vm_context: &VmContext) 564 | -> bool { 565 | let mut instruction_iter = vm_handler.instructions.iter(); 566 | let mov_to_vip = 567 | instruction_iter.find(|insn| { 568 | match_fetch_reg_any_size(insn, vm_context.register_allocation.vsp.into()).is_some() 569 | }); 570 | 571 | if mov_to_vip.is_none() { 572 | return false; 573 | } 574 | 575 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 576 | 577 | let add_vsp_instruction = 578 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, &vm_context.register_allocation).is_some()); 579 | 580 | if add_vsp_instruction.is_none() { 581 | return false; 582 | } 583 | 584 | if add_vsp_instruction.unwrap().immediate32() != 8 { 585 | return false; 586 | } 587 | 588 | let mut cloned_iter = instruction_iter.clone(); 589 | let mov_vip = cloned_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 590 | let new_vip = match mov_vip { 591 | Some(mov_vip) => { 592 | let potential_vip = mov_vip.op0_register().full_register(); 593 | if cloned_iter.any(|insn| match_sub_reg_left(insn, potential_vip)) { 594 | new_vip 595 | } else { 596 | potential_vip 597 | } 598 | }, 599 | None => new_vip, 600 | }; 601 | 602 | let _mov_vsp = 603 | instruction_iter.find(|insn| { 604 | match_mov_reg_source(insn, vm_context.register_allocation.vsp.into()) 605 | }); 606 | 607 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 608 | 609 | if store_key_reg.is_none() { 610 | return false; 611 | } 612 | 613 | instruction_iter.any(|insn| match_sub_reg_by_amount(insn, new_vip, 4)) 614 | } 615 | 616 | fn vm_match_jmp_inc_vsp_change(vm_handler: &VmHandler, 617 | vm_context: &VmContext) 618 | -> bool { 619 | let mut instruction_iter = vm_handler.instructions.iter(); 620 | let mov_to_vip = 621 | instruction_iter.find(|insn| { 622 | match_fetch_reg_any_size(insn, vm_context.register_allocation.vsp.into()).is_some() 623 | }); 624 | 625 | if mov_to_vip.is_none() { 626 | return false; 627 | } 628 | 629 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 630 | 631 | let add_vsp_instruction = 632 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, &vm_context.register_allocation).is_some()); 633 | 634 | if add_vsp_instruction.is_none() { 635 | return false; 636 | } 637 | 638 | if add_vsp_instruction.unwrap().immediate32() != 8 { 639 | return false; 640 | } 641 | 642 | let mut cloned_iter = instruction_iter.clone(); 643 | let mov_vip = cloned_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 644 | let new_vip = match mov_vip { 645 | Some(mov_vip) => { 646 | let potential_vip = mov_vip.op0_register().full_register(); 647 | if cloned_iter.any(|insn| match_sub_reg_left(insn, potential_vip)) { 648 | new_vip 649 | } else { 650 | potential_vip 651 | } 652 | }, 653 | None => new_vip, 654 | }; 655 | 656 | let _mov_vsp = 657 | instruction_iter.find(|insn| { 658 | match_mov_reg_source(insn, vm_context.register_allocation.vsp.into()) 659 | }); 660 | 661 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip)); 662 | 663 | if store_key_reg.is_none() { 664 | return false; 665 | } 666 | 667 | instruction_iter.any(|insn| match_add_reg_by_amount(insn, new_vip, 4)) 668 | } 669 | 670 | fn vm_match_jmp_dec_vsp_xchng(vm_handler: &VmHandler, 671 | vm_context: &VmContext) 672 | -> bool { 673 | let mut instruction_iter = vm_handler.instructions.iter(); 674 | let mov_to_vip = 675 | instruction_iter.find(|insn| { 676 | match_fetch_reg_any_size(insn, vm_context.register_allocation.vsp.into()).is_some() 677 | }); 678 | 679 | if mov_to_vip.is_none() { 680 | return false; 681 | } 682 | 683 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 684 | 685 | let add_vsp_instruction = 686 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, &vm_context.register_allocation).is_some()); 687 | 688 | if add_vsp_instruction.is_none() { 689 | return false; 690 | } 691 | 692 | if add_vsp_instruction.unwrap().immediate32() != 8 { 693 | return false; 694 | } 695 | 696 | let xchng = instruction_iter.find(|insn| match_xchng_reg(insn, new_vip)); 697 | 698 | let new_vip_reg; 699 | match xchng { 700 | Some(xchng_insn) => { 701 | if !(xchng_insn.op0_register() == new_vip && 702 | xchng_insn.op1_register() == vm_context.register_allocation.vsp.into()) && 703 | !(xchng_insn.op1_register() == new_vip && 704 | xchng_insn.op0_register() == vm_context.register_allocation.vsp.into()) 705 | { 706 | return false; 707 | } else { 708 | new_vip_reg = vm_context.register_allocation.vsp.into(); 709 | } 710 | }, 711 | None => return false, 712 | } 713 | 714 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip_reg)); 715 | 716 | if store_key_reg.is_none() { 717 | return false; 718 | } 719 | 720 | instruction_iter.any(|insn| match_sub_reg_by_amount(insn, new_vip_reg, 4)) 721 | } 722 | 723 | fn vm_match_jmp_inc_vsp_xchng(vm_handler: &VmHandler, 724 | vm_context: &VmContext) 725 | -> bool { 726 | let mut instruction_iter = vm_handler.instructions.iter(); 727 | let mov_to_vip = 728 | instruction_iter.find(|insn| { 729 | match_fetch_reg_any_size(insn, vm_context.register_allocation.vsp.into()).is_some() 730 | }); 731 | 732 | if mov_to_vip.is_none() { 733 | return false; 734 | } 735 | 736 | let new_vip = mov_to_vip.unwrap().op0_register().full_register(); 737 | 738 | let add_vsp_instruction = 739 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, &vm_context.register_allocation).is_some()); 740 | 741 | if add_vsp_instruction.is_none() { 742 | return false; 743 | } 744 | 745 | if add_vsp_instruction.unwrap().immediate32() != 8 { 746 | return false; 747 | } 748 | 749 | let xchng = instruction_iter.find(|insn| match_xchng_reg(insn, new_vip)); 750 | 751 | let new_vip_reg; 752 | match xchng { 753 | Some(xchng_insn) => { 754 | if !(xchng_insn.op0_register() == new_vip && 755 | xchng_insn.op1_register() == vm_context.register_allocation.vsp.into()) && 756 | !(xchng_insn.op1_register() == new_vip && 757 | xchng_insn.op0_register() == vm_context.register_allocation.vsp.into()) 758 | { 759 | return false; 760 | } else { 761 | new_vip_reg = vm_context.register_allocation.vsp.into(); 762 | } 763 | }, 764 | None => return false, 765 | } 766 | 767 | let store_key_reg = instruction_iter.find(|insn| match_mov_reg_source(insn, new_vip_reg)); 768 | 769 | if store_key_reg.is_none() { 770 | return false; 771 | } 772 | 773 | instruction_iter.any(|insn| match_add_reg_by_amount(insn, new_vip_reg, 4)) 774 | } 775 | /// Match a pop of a vmregister 776 | fn vm_match_vm_reg_pop(vm_handler: &VmHandler, 777 | reg_allocation: &VmRegisterAllocation) 778 | -> Option { 779 | let mut instruction_iter = vm_handler.instructions.iter(); 780 | instruction_iter.find(|insn| { 781 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 782 | }); 783 | let _add_vsp_instruction = 784 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, reg_allocation).is_some()); 785 | 786 | let vip_byte_fetch_instruction = 787 | instruction_iter.find(|insn| { 788 | match_fetch_reg_any_size(insn, reg_allocation.vip.into()).is_some() 789 | })?; 790 | 791 | let index_reg = vip_byte_fetch_instruction.op0_register().full_register(); 792 | 793 | let store_vm_reg = instruction_iter.find(|insn| match_store_vm_reg(insn, index_reg)); 794 | store_vm_reg.map(|insn| insn.memory_size().size()) 795 | } 796 | 797 | /// Match a pop of a vmregister (different vmp3 version maybe idk) 798 | fn vm_match_vm_reg_pop_v2(vm_handler: &VmHandler, 799 | reg_allocation: &VmRegisterAllocation) 800 | -> Option { 801 | let mut instruction_iter = vm_handler.instructions.iter(); 802 | let vip_byte_fetch_instruction = 803 | instruction_iter.find(|insn| { 804 | match_fetch_reg_any_size(insn, reg_allocation.vip.into()).is_some() 805 | })?; 806 | 807 | let index_reg = vip_byte_fetch_instruction.op0_register().full_register(); 808 | 809 | instruction_iter.find(|insn| { 810 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 811 | }); 812 | 813 | let _add_vsp_instruction = 814 | instruction_iter.find(|insn| match_add_vsp_get_amount(insn, reg_allocation).is_some()); 815 | 816 | let store_vm_reg = instruction_iter.find(|insn| match_store_vm_reg(insn, index_reg)); 817 | store_vm_reg.map(|insn| insn.memory_size().size()) 818 | } 819 | /// Match a push of a vmregister 820 | fn vm_match_vm_reg_push(vm_handler: &VmHandler, 821 | reg_allocation: &VmRegisterAllocation) 822 | -> Option { 823 | let mut instruction_iter = vm_handler.instructions.iter(); 824 | 825 | let vip_byte_fetch_instruction = 826 | instruction_iter.find(|insn| { 827 | match_fetch_reg_any_size(insn, reg_allocation.vip.into()).is_some() 828 | })?; 829 | 830 | let index_reg = vip_byte_fetch_instruction.op0_register().full_register(); 831 | 832 | let fetch_vm_reg = instruction_iter.find(|insn| match_fetch_vm_reg(insn, index_reg)); 833 | 834 | let _sub_vsp_instruction = 835 | instruction_iter.find(|insn| match_sub_vsp_get_amount(insn, reg_allocation).is_some()); 836 | 837 | instruction_iter.find(|insn| { 838 | match_store_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 839 | })?; 840 | 841 | fetch_vm_reg.map(|insn| insn.memory_size().size()) 842 | } 843 | 844 | /// Match a n byte imm push 845 | fn match_push_imm_n(vm_handler: &VmHandler, 846 | reg_allocation: &VmRegisterAllocation) 847 | -> bool { 848 | let mut instruction_iter = vm_handler.instructions.iter(); 849 | instruction_iter.find(|insn| match_sub_vsp_by_amount(insn, reg_allocation, N)); 850 | instruction_iter.any(|insn| match_store_reg_any_size(insn, reg_allocation.vsp.into()).is_some()) 851 | } 852 | 853 | /// Match 64 bit imm push 854 | fn vm_match_push_imm64(vm_handler: &VmHandler, 855 | reg_allocation: &VmRegisterAllocation) 856 | -> bool { 857 | match_push_imm_n::<8>(vm_handler, reg_allocation) 858 | } 859 | 860 | /// Match 32 bit imm push 861 | fn vm_match_push_imm32(vm_handler: &VmHandler, 862 | reg_allocation: &VmRegisterAllocation) 863 | -> bool { 864 | match_push_imm_n::<4>(vm_handler, reg_allocation) 865 | } 866 | 867 | /// Match 16 bit imm push 868 | fn vm_match_push_imm16(vm_handler: &VmHandler, 869 | reg_allocation: &VmRegisterAllocation) 870 | -> bool { 871 | match_push_imm_n::<2>(vm_handler, reg_allocation) 872 | } 873 | 874 | /// Match 8 bit imm push 875 | fn vm_match_push_imm8(vm_handler: &VmHandler, 876 | reg_allocation: &VmRegisterAllocation) 877 | -> bool { 878 | // Push of byte is sign extended 879 | match_push_imm_n::<2>(vm_handler, reg_allocation) 880 | } 881 | 882 | fn vm_match_pop_vsp_64(vm_handler: &VmHandler, 883 | reg_allocation: &VmRegisterAllocation) 884 | -> bool { 885 | let mut instruction_iter = vm_handler.instructions.iter(); 886 | 887 | let fetch_vsp_instruction_1 = 888 | instruction_iter.find(|insn| { 889 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 890 | }); 891 | if fetch_vsp_instruction_1.is_none() { 892 | return false; 893 | } 894 | 895 | fetch_vsp_instruction_1.unwrap().op0_register() == reg_allocation.vsp.into() 896 | } 897 | 898 | macro_rules! generate_binop_match { 899 | ($matcher_name:ident, $specific_matcher:expr) => { 900 | 901 | fn $matcher_name(vm_handler: &VmHandler, 902 | reg_allocation: &VmRegisterAllocation) 903 | -> Option { 904 | let mut instruction_iter = vm_handler.instructions.iter(); 905 | 906 | let fetch_vsp_instruction_1 = 907 | instruction_iter.find(|insn| { 908 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 909 | })?; 910 | let reg1 = fetch_vsp_instruction_1.op0_register().full_register(); 911 | 912 | let fetch_vsp_instruction_2 = 913 | instruction_iter.find(|insn| { 914 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 915 | })?; 916 | let reg2 = fetch_vsp_instruction_2.op0_register().full_register(); 917 | 918 | let instruction_size = fetch_vsp_instruction_1.memory_size().size(); 919 | 920 | $specific_matcher (&mut instruction_iter, reg1, reg2)?; 921 | 922 | instruction_iter.find(|insn| match_pushfq(insn))?; 923 | 924 | Some(instruction_size) 925 | } 926 | }; 927 | } 928 | 929 | macro_rules! generate_binop_match_byte { 930 | ($matcher_name:ident, $specific_matcher:expr) => { 931 | 932 | fn $matcher_name(vm_handler: &VmHandler, 933 | reg_allocation: &VmRegisterAllocation) 934 | -> Option { 935 | let mut instruction_iter = vm_handler.instructions.iter(); 936 | 937 | let fetch_vsp_instruction_1 = 938 | instruction_iter.find(|insn| { 939 | match_fetch_zx_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 940 | })?; 941 | let reg1 = fetch_vsp_instruction_1.op0_register().full_register(); 942 | 943 | let fetch_vsp_instruction_2 = 944 | instruction_iter.find(|insn| { 945 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 946 | })?; 947 | let reg2 = fetch_vsp_instruction_2.op0_register().full_register(); 948 | 949 | let instruction_size = fetch_vsp_instruction_1.memory_size().size(); 950 | 951 | $specific_matcher (&mut instruction_iter, reg1, reg2)?; 952 | 953 | instruction_iter.find(|insn| match_pushfq(insn))?; 954 | 955 | Some(instruction_size) 956 | } 957 | }; 958 | } 959 | 960 | fn sub_match_add<'a, I>(instruction_iter: &mut I, 961 | reg1: Register, 962 | reg2: Register) 963 | -> Option<&'a Instruction> 964 | where I: Iterator 965 | { 966 | instruction_iter.find(|insn| match_add_reg_reg(insn, reg1, reg2)) 967 | } 968 | generate_binop_match!(vm_match_add, sub_match_add); 969 | generate_binop_match_byte!(vm_match_add_byte, sub_match_add); 970 | 971 | fn sub_match_mul<'a, I>(instruction_iter: &mut I, 972 | reg1: Register, 973 | reg2: Register) 974 | -> Option<&'a Instruction> 975 | where I: Iterator 976 | { 977 | instruction_iter.find(|insn| match_mul_reg_reg(insn, reg1, reg2)) 978 | } 979 | 980 | fn sub_match_imul<'a, I>(instruction_iter: &mut I, 981 | reg1: Register, 982 | reg2: Register) 983 | -> Option<&'a Instruction> 984 | where I: Iterator 985 | { 986 | instruction_iter.find(|insn| match_imul_reg_reg(insn, reg1, reg2)) 987 | } 988 | 989 | generate_binop_match!(vm_match_mul, sub_match_mul); 990 | generate_binop_match!(vm_match_imul, sub_match_imul); 991 | 992 | fn sub_match_nand<'a, I>(instruction_iter: &mut I, 993 | reg1: Register, 994 | reg2: Register) 995 | -> Option<&'a Instruction> 996 | where I: Iterator 997 | { 998 | instruction_iter.find(|insn| match_not_reg(insn, reg1))?; 999 | instruction_iter.find(|insn| match_not_reg(insn, reg2))?; 1000 | 1001 | instruction_iter.find(|insn| match_or_reg_reg(insn, reg1, reg2)) 1002 | } 1003 | 1004 | generate_binop_match!(vm_match_nand, sub_match_nand); 1005 | generate_binop_match_byte!(vm_match_nand_byte, sub_match_nand); 1006 | 1007 | fn sub_match_nor<'a, I>(instruction_iter: &mut I, 1008 | reg1: Register, 1009 | reg2: Register) 1010 | -> Option<&'a Instruction> 1011 | where I: Iterator 1012 | { 1013 | instruction_iter.find(|insn| match_not_reg(insn, reg1))?; 1014 | instruction_iter.find(|insn| match_not_reg(insn, reg2))?; 1015 | 1016 | instruction_iter.find(|insn| match_and_reg_reg(insn, reg1, reg2)) 1017 | } 1018 | 1019 | generate_binop_match!(vm_match_nor, sub_match_nor); 1020 | generate_binop_match_byte!(vm_match_nor_byte, sub_match_nor); 1021 | 1022 | macro_rules! generate_binop_match_single_reg { 1023 | ($matcher_name:ident, $specific_matcher:expr) => { 1024 | 1025 | fn $matcher_name(vm_handler: &VmHandler, 1026 | reg_allocation: &VmRegisterAllocation) 1027 | -> Option { 1028 | let mut instruction_iter = vm_handler.instructions.iter(); 1029 | 1030 | let fetch_vsp_instruction_1 = 1031 | instruction_iter.find(|insn| { 1032 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1033 | })?; 1034 | let reg = fetch_vsp_instruction_1.op0_register(); 1035 | 1036 | let _fetch_vsp_instruction_2 = 1037 | instruction_iter.find(|insn| { 1038 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1039 | })?; 1040 | 1041 | let instruction_size = fetch_vsp_instruction_1.memory_size().size(); 1042 | 1043 | $specific_matcher (&mut instruction_iter, reg)?; 1044 | 1045 | instruction_iter.find(|insn| match_pushfq(insn))?; 1046 | 1047 | Some(instruction_size) 1048 | } 1049 | }; 1050 | } 1051 | 1052 | macro_rules! generate_binop_match_byte_single_reg { 1053 | ($matcher_name:ident, $specific_matcher:expr) => { 1054 | 1055 | fn $matcher_name(vm_handler: &VmHandler, 1056 | reg_allocation: &VmRegisterAllocation) 1057 | -> Option { 1058 | let mut instruction_iter = vm_handler.instructions.iter(); 1059 | 1060 | let fetch_vsp_instruction_1 = 1061 | instruction_iter.find(|insn| { 1062 | match_fetch_zx_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1063 | })?; 1064 | let reg = fetch_vsp_instruction_1.op0_register().full_register(); 1065 | 1066 | let _fetch_vsp_instruction_2 = 1067 | instruction_iter.find(|insn| { 1068 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1069 | })?; 1070 | 1071 | let instruction_size = fetch_vsp_instruction_1.memory_size().size(); 1072 | 1073 | $specific_matcher (&mut instruction_iter, reg.full_register())?; 1074 | 1075 | instruction_iter.find(|insn| match_pushfq(insn))?; 1076 | 1077 | Some(instruction_size) 1078 | } 1079 | }; 1080 | } 1081 | 1082 | fn sub_match_shr<'a, I>(instruction_iter: &mut I, 1083 | reg: Register) 1084 | -> Option<&'a Instruction> 1085 | where I: Iterator 1086 | { 1087 | instruction_iter.find(|insn| match_shr_reg_reg(insn, reg)) 1088 | } 1089 | 1090 | generate_binop_match_single_reg!(vm_match_shr, sub_match_shr); 1091 | generate_binop_match_byte_single_reg!(vm_match_shr_byte, sub_match_shr); 1092 | 1093 | fn sub_match_shl<'a, I>(instruction_iter: &mut I, 1094 | reg: Register) 1095 | -> Option<&'a Instruction> 1096 | where I: Iterator 1097 | { 1098 | instruction_iter.find(|insn| match_shl_reg_reg(insn, reg)) 1099 | } 1100 | 1101 | generate_binop_match_single_reg!(vm_match_shl, sub_match_shl); 1102 | generate_binop_match_byte_single_reg!(vm_match_shl_byte, sub_match_shl); 1103 | 1104 | fn sub_match_shrd<'a, I>(instruction_iter: &mut I, 1105 | reg: Register) 1106 | -> Option<&'a Instruction> 1107 | where I: Iterator 1108 | { 1109 | instruction_iter.find(|insn| match_shrd_reg_reg(insn, reg)) 1110 | } 1111 | 1112 | generate_binop_match_single_reg!(vm_match_shrd, sub_match_shrd); 1113 | 1114 | fn sub_match_shld<'a, I>(instruction_iter: &mut I, 1115 | reg: Register) 1116 | -> Option<&'a Instruction> 1117 | where I: Iterator 1118 | { 1119 | instruction_iter.find(|insn| match_shld_reg_reg(insn, reg)) 1120 | } 1121 | 1122 | generate_binop_match_single_reg!(vm_match_shld, sub_match_shld); 1123 | 1124 | fn vm_match_fetch(vm_handler: &VmHandler, 1125 | reg_allocation: &VmRegisterAllocation) 1126 | -> Option { 1127 | let mut instruction_iter = vm_handler.instructions.iter(); 1128 | let fetch_vsp_instruction = 1129 | instruction_iter.find(|insn| { 1130 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1131 | })?; 1132 | 1133 | let fetch_register = fetch_vsp_instruction.op0_register(); 1134 | 1135 | let mut fetch_size = 0; 1136 | instruction_iter.find(|insn| { 1137 | if let Some(size) = match_fetch_reg_any_size(insn, fetch_register) { 1138 | fetch_size = size; 1139 | true 1140 | } else { 1141 | false 1142 | } 1143 | })?; 1144 | 1145 | Some(fetch_size) 1146 | } 1147 | 1148 | fn vm_match_fetch_byte(vm_handler: &VmHandler, 1149 | reg_allocation: &VmRegisterAllocation) 1150 | -> Option { 1151 | let mut instruction_iter = vm_handler.instructions.iter(); 1152 | let fetch_vsp_instruction = 1153 | instruction_iter.find(|insn| { 1154 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1155 | })?; 1156 | 1157 | let fetch_register = fetch_vsp_instruction.op0_register().full_register(); 1158 | 1159 | let mut fetch_size = 0; 1160 | instruction_iter.find(|insn| { 1161 | if let Some(size) = match_fetch_zx_reg_any_size(insn, fetch_register) { 1162 | fetch_size = size; 1163 | true 1164 | } else { 1165 | false 1166 | } 1167 | })?; 1168 | 1169 | Some(fetch_size) 1170 | } 1171 | 1172 | fn vm_match_store(vm_handler: &VmHandler, 1173 | reg_allocation: &VmRegisterAllocation) 1174 | -> Option { 1175 | let mut instruction_iter = vm_handler.instructions.iter(); 1176 | 1177 | let fetch_vsp_instruction_1 = 1178 | instruction_iter.find(|insn| { 1179 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1180 | })?; 1181 | 1182 | let reg1 = fetch_vsp_instruction_1.op0_register().full_register(); 1183 | 1184 | let fetch_vsp_instruction_2 = 1185 | instruction_iter.find(|insn| { 1186 | match_fetch_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1187 | })?; 1188 | 1189 | let reg2 = fetch_vsp_instruction_2.op0_register().full_register(); 1190 | 1191 | let mut instruction_size = 0; 1192 | instruction_iter.find(|insn| match match_store_reg2_in_reg1(insn, reg1, reg2) { 1193 | Some(size) => { 1194 | instruction_size = size; 1195 | true 1196 | }, 1197 | _ => false, 1198 | })?; 1199 | Some(instruction_size) 1200 | } 1201 | 1202 | fn vm_match_push_vsp(vm_handler: &VmHandler, 1203 | reg_allocation: &VmRegisterAllocation) 1204 | -> Option { 1205 | let mut instruction_iter = vm_handler.instructions.iter(); 1206 | instruction_iter.find(|insn| match_mov_reg_source(insn, reg_allocation.vsp.into()))?; 1207 | 1208 | let sub_vsp_instruction = 1209 | instruction_iter.find(|insn| match_sub_vsp_get_amount(insn, reg_allocation).is_some())?; 1210 | let instruction_size = sub_vsp_instruction.immediate32(); 1211 | instruction_iter.find(|insn| { 1212 | match_store_reg_any_size(insn, reg_allocation.vsp.into()).is_some() 1213 | })?; 1214 | 1215 | Some(instruction_size as usize) 1216 | } 1217 | 1218 | fn vm_match_vm_exit(vm_handler: &VmHandler, 1219 | reg_allocation: &VmRegisterAllocation) 1220 | -> bool { 1221 | let instruction_iter = vm_handler.instructions.iter(); 1222 | 1223 | if !instruction_iter.clone().any(match_ret) { 1224 | return false; 1225 | } 1226 | 1227 | if !instruction_iter.clone().any(match_popfq) { 1228 | return false; 1229 | } 1230 | 1231 | if !instruction_iter.clone().any(|insn| { 1232 | insn.code() == Code::Mov_r64_rm64 && 1233 | insn.op0_register() == Register::RSP && 1234 | insn.op1_register() == reg_allocation.vsp.into() 1235 | }) 1236 | { 1237 | return false; 1238 | } 1239 | 1240 | if instruction_iter.filter(|insn| insn.code() == Code::Pop_r64) 1241 | .count() != 1242 | 15 1243 | { 1244 | return false; 1245 | } 1246 | 1247 | true 1248 | } 1249 | 1250 | fn vm_match_push_cr0(vm_handler: &VmHandler) -> bool { 1251 | let first_instruction = vm_handler.instructions[0]; 1252 | (first_instruction.code() == Code::Mov_r64_cr) && 1253 | first_instruction.op1_register() == Register::CR0 1254 | } 1255 | 1256 | fn vm_match_push_cr3(vm_handler: &VmHandler) -> bool { 1257 | let first_instruction = vm_handler.instructions[0]; 1258 | (first_instruction.code() == Code::Mov_r64_cr) && 1259 | first_instruction.op1_register() == Register::CR3 1260 | } 1261 | 1262 | fn vm_match_rdtsc(vm_handler: &VmHandler) -> bool { 1263 | let first_instruction = vm_handler.instructions[0]; 1264 | first_instruction.code() == Code::Rdtsc 1265 | } 1266 | 1267 | fn vm_match_nop(vm_handler: &VmHandler) -> bool { 1268 | let first_instruction = vm_handler.instructions[0]; 1269 | first_instruction.code() == Code::Lea_r64_m 1270 | } 1271 | 1272 | // fn match_lock_xchng(vm_handler: &VmHandler) -> bool { 1273 | // let mut instruction_iter = vm_handler.instructions.iter(); 1274 | // instruction_iter.any(|insn| insn.code() == Code::Xchg_rm64_r64 && insn.has_lock_prefix()) 1275 | // } 1276 | --------------------------------------------------------------------------------