├── .gitignore ├── Cargo.toml ├── README.md └── src ├── config.rs ├── emu ├── banzai.rs ├── breakpoint.rs ├── colors.rs ├── console.rs ├── constants.rs ├── context32.rs ├── context64.rs ├── eflags.rs ├── elf32.rs ├── elf64.rs ├── endpoint.rs ├── err.rs ├── exception.rs ├── flags.rs ├── fpu.rs ├── hook.rs ├── inline.rs ├── macros.rs ├── maps.rs ├── maps │ └── mem64.rs ├── mod.rs ├── ntapi32.rs ├── pe32.rs ├── pe64.rs ├── peb32.rs ├── peb64.rs ├── regs64.rs ├── script.rs ├── structures.rs ├── syscall32.rs ├── syscall64.rs ├── winapi32.rs ├── winapi32 │ ├── advapi32.rs │ ├── crypt32.rs │ ├── dnsapi.rs │ ├── helper.rs │ ├── iphlpapi.rs │ ├── kernel32.rs │ ├── kernelbase.rs │ ├── libgcc.rs │ ├── mscoree.rs │ ├── msvcrt.rs │ ├── ntdll.rs │ ├── oleaut32.rs │ ├── shlwapi.rs │ ├── user32.rs │ ├── wincrt.rs │ ├── wininet.rs │ └── ws2_32.rs ├── winapi64.rs └── winapi64 │ ├── advapi32.rs │ ├── comctl64.rs │ ├── dnsapi.rs │ ├── kernel32.rs │ ├── kernelbase.rs │ ├── ntdll.rs │ ├── shell32.rs │ ├── shlwapi.rs │ ├── user32.rs │ ├── winhttp.rs │ ├── wininet.rs │ └── ws2_32.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libscemu" 3 | version = "0.19.3" 4 | edition = "2018" 5 | authors = ["sha0coder"] 6 | license = "MIT" 7 | description = "x86 32/64bits and system internals emulator, for securely emulating malware and other stuff." 8 | #email = "sha0 at badchecksum.net" 9 | documentation = "https://docs.rs/libscemu/0.4.15/libscemu/" 10 | repository = "https://github.com/sha0coder/libscemu" 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | iced-x86 = "1.19.0" 15 | uint = "0.9.5" 16 | md5 = "0.7.0" 17 | lazy_static = "1.4.0" 18 | #attohttpc = "0.18.0" 19 | rand = "0.8.4" 20 | ctrlc = "3.2.2" 21 | scan_fmt = "0.2.6" 22 | atty = "0.2.14" 23 | csv = "1.3.0" 24 | chrono = { version = "0.4", features = ["serde"] } 25 | log = "0.4.22" 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # SCEMU the lib 3 | 4 | This repo has been archived, now libscemu, pyscemu and scemu become 1 repo: 5 | https://github.com/sha0coder/mwemu 6 | 7 | 8 | 9 | 10 | ## Usage 11 | 12 | Download the maps32 or maps64 from: 13 | https://github.com/sha0coder/scemu 14 | 15 | In the example it's on /tmp/ but dont use tmp. 16 | 17 | Create an emu32 or emu64 and it's important to set the maps folder. 18 | 19 | ```rust 20 | use libscemu::emu32; 21 | 22 | 23 | fn main() { 24 | let mut emu = emu32(); 25 | emu.set_maps_folder("/tmp/maps32/"); 26 | emu.init(false, false); 27 | ``` 28 | 29 | Load your shellcode or PE binary and run the emulator. 30 | None parameter means emulate for-ever. 31 | 32 | ```rust 33 | emu.load_code("shellcodes32/shikata.bin"); 34 | emu.set_verbose(2); 35 | emu.run(None).unwrap(); 36 | ``` 37 | 38 | Or if you prefer call specific function. 39 | 40 | ```rust 41 | emu.load_code("samples/malware.exe"); 42 | 43 | let crypto_key_gen = 0x40112233; 44 | let ret_addr = 0x40110000; // any place safe to return. 45 | 46 | let param1 = 0x33; 47 | let param2_out_buff = emu.alloc("buffer", 1024); 48 | 49 | emu.maps.memset(param2_out_buff, 0, 1024); // non necesary, by default alloc create zeros. 50 | emu.maps.write_spaced_bytes(param2_out_buff, 51 | "DE CC 6C 83 CC F3 66 85 34"); // example of initialization. 52 | 53 | // call function 54 | emu.regs.set_eip(crypto_key_gen); 55 | emu.stack_push32(param2_out_buff); 56 | emu.stack_push32(param1); 57 | emu.stack_push32(ret_addr); 58 | emu.run(Some(ret_addr)).unwrap(); // emulate until arrive to ret_addr 59 | 60 | // or simpler way: 61 | let eax = emu.call32(crypto_key_gen, &[param1, param2_out_buff]).unwrap(); 62 | 63 | // this would be slower but more control 64 | while emu.step() { 65 | ... 66 | } 67 | 68 | // check result 69 | log::info!("return value: 0x{:x}", emu.regs.get_eax()); 70 | emu.maps.dump(param2_out_buff); 71 | ``` 72 | 73 | Now it's possible to do hooks on libscemu but not on pyscemu. 74 | 75 | ```rust 76 | use libscemu::emu32; 77 | 78 | //need iced_x86 crate only for instruction hooks, to get the 79 | //instruction object, so add `iced-x86 = "1.17.0"` 80 | use iced_x86::{Instruction}; 81 | 82 | 83 | fn trace_memory_read(emu:&mut libscemu::emu::Emu, ip_addr:u64, 84 | mem_addr:u64, sz:u8) { 85 | log::info!("0x{:x}: reading {} at 0x{:x}", ip_addr, sz, mem_addr); 86 | if mem_addr == 0x22dff0 { 87 | emu.stop(); 88 | } 89 | } 90 | 91 | fn trace_memory_write(emu:&mut libscemu::emu::Emu, ip_addr:u64, 92 | mem_addr:u64, sz:u8, value:u128) -> u128 { 93 | log::info!("0x{:x}: writing {} '0x{:x}' at 0x{:x}", ip_addr, sz, 94 | value, mem_addr); 95 | value // I could change the value to write 96 | } 97 | 98 | fn trace_interrupt(emu:&mut libscemu::emu::Emu, ip_addr:u64, 99 | interrupt:u64) -> bool { 100 | log::info!("interrupt {} triggered at eip: 0x{:x}", interrupt, 101 | ip_addr); 102 | true // do handle interrupts 103 | } 104 | 105 | fn trace_exceptions(emu:&mut libscemu::emu::Emu, ip_addr:u64) -> bool { 106 | log::info!("0x{:x} triggered an exception", ip_addr); 107 | true // do handle exceptions 108 | } 109 | 110 | fn trace_pre_instruction(emu:&mut libscemu::emu::Emu, ip_addr:u64, 111 | ins:&Instruction, sz:usize) { 112 | } 113 | 114 | fn trace_post_instruction(emu:&mut libscemu::emu::Emu, ip_addr:u64, 115 | ins:&Instruction, sz:usize, emu_ok:bool) { 116 | } 117 | 118 | fn trace_winapi_call(emu:&mut libscemu::emu::Emu, ip_addr:u64, api_addr:u64) -> bool { 119 | return true; // handle api calls 120 | } 121 | 122 | fn main() { 123 | let mut emu = emu32(); 124 | emu.set_maps_folder("../scemu/maps32/"); // download the maps, ideally from scemu git. 125 | emu.init(); 126 | 127 | emu.load_code("/home/sha0/src/scemu/shellcodes32/mars.exe"); 128 | emu.hook.on_memory_read(trace_memory_read); 129 | emu.hook.on_memory_write(trace_memory_write); 130 | emu.hook.on_interrupt(trace_interrupt); 131 | emu.hook.on_exception(trace_exceptions); 132 | emu.hook.on_pre_instruction(trace_pre_instruction); 133 | emu.hook.on_post_instruction(trace_post_instruction); 134 | emu.hook.on_winapi_call(trace_winapi_call); 135 | emu.run(None).unwrap(); 136 | log::info!("end!"); 137 | } 138 | ``` 139 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | pub struct Config { 2 | pub filename: String, // filename with full path included 3 | pub trace_mem: bool, // show memory operations in every step. 4 | pub trace_regs: bool, // show all the regs in every step. 5 | pub trace_reg: bool, // show value and content of a reg in every step. 6 | pub reg_names: Vec, // which reg to trace. 7 | pub verbose: u32, // 0 only view the api, 1 api + messages, 2 asm code. 8 | pub console: bool, // enable the console on specific moment?. 9 | pub console_num: u64, // in which moment enable the console. 10 | pub loops: bool, // loop mode count the iterations for every instruction, its slow. 11 | pub nocolors: bool, // to redirecting the output to a file is better to remove colors. 12 | pub trace_string: bool, 13 | pub string_addr: u64, 14 | pub inspect: bool, 15 | pub inspect_seq: String, 16 | pub endpoint: bool, 17 | pub maps_folder: String, 18 | pub console2: bool, 19 | pub console_addr: u64, 20 | pub entry_point: u64, 21 | pub exit_position: u64, 22 | pub code_base_addr: u64, 23 | pub is_64bits: bool, // 64bits mode 24 | pub stack_trace: bool, 25 | pub test_mode: bool, 26 | pub console_enabled: bool, 27 | pub skip_unimplemented: bool, 28 | pub stack_addr: u64, 29 | pub trace_file: Option, 30 | } 31 | 32 | impl Config { 33 | pub fn new() -> Config { 34 | Config { 35 | filename: String::new(), 36 | trace_mem: false, 37 | trace_regs: false, 38 | trace_reg: false, 39 | reg_names: Vec::new(), 40 | verbose: 0, 41 | console: false, 42 | console_num: 0, 43 | loops: false, 44 | nocolors: false, 45 | trace_string: false, 46 | string_addr: 0, 47 | inspect: false, 48 | inspect_seq: "".to_string(), 49 | endpoint: false, 50 | maps_folder: "".to_string(), 51 | console2: false, 52 | console_addr: 0, 53 | entry_point: 0x3c0000, 54 | exit_position: 0, 55 | code_base_addr: 0x3c0000, 56 | is_64bits: false, 57 | stack_trace: false, 58 | test_mode: false, 59 | console_enabled: true, 60 | skip_unimplemented: false, 61 | stack_addr: 0, 62 | trace_file: None, 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/emu/breakpoint.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct Breakpoint { 3 | addr: u64, 4 | instruction: u64, 5 | mem_read_addr: u64, 6 | mem_write_addr: u64, 7 | } 8 | 9 | impl Breakpoint { 10 | pub fn new() -> Breakpoint { 11 | Breakpoint { 12 | addr: 0, 13 | instruction: 0, 14 | mem_read_addr: 0, 15 | mem_write_addr: 0, 16 | } 17 | } 18 | 19 | pub fn set_bp(&mut self, addr: u64) { 20 | self.addr = addr; 21 | } 22 | 23 | pub fn clear_bp(&mut self) { 24 | self.addr = 0; 25 | self.mem_read_addr = 0; 26 | self.mem_write_addr = 0; 27 | } 28 | 29 | pub fn set_mem_read(&mut self, addr: u64) { 30 | self.mem_read_addr = addr; 31 | } 32 | 33 | pub fn set_mem_write(&mut self, addr: u64) { 34 | self.mem_write_addr = addr; 35 | } 36 | 37 | pub fn set_instruction(&mut self, ins: u64) { 38 | self.instruction = ins; 39 | } 40 | 41 | pub fn get_bp(&self) -> u64 { 42 | return self.addr; 43 | } 44 | 45 | pub fn get_mem_read(&self) -> u64 { 46 | return self.mem_read_addr; 47 | } 48 | 49 | pub fn get_mem_write(&self) -> u64 { 50 | return self.mem_write_addr; 51 | } 52 | 53 | pub fn get_instruction(&self) -> u64 { 54 | return self.instruction; 55 | } 56 | 57 | pub fn show(&self) { 58 | log::info!("break on address: 0x{:x}", self.addr); 59 | log::info!("break on instruction: {}", self.instruction); 60 | log::info!("break on memory read: 0x{:x}", self.mem_read_addr); 61 | log::info!("break on memory write: 0x{:x}", self.mem_write_addr); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/emu/colors.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct Colors { 3 | pub black: String, 4 | pub red: String, 5 | pub green: String, 6 | pub orange: String, 7 | pub blue: String, 8 | pub purple: String, 9 | pub cyan: String, 10 | pub light_gray: String, 11 | pub dark_gray: String, 12 | pub light_red: String, 13 | pub light_green: String, 14 | pub yellow: String, 15 | pub light_blue: String, 16 | pub light_purple: String, 17 | pub light_cyan: String, 18 | pub white: String, 19 | pub nc: String, // no_color 20 | pub clear_screen: String, 21 | } 22 | 23 | impl Colors { 24 | pub fn new() -> Colors { 25 | Colors { 26 | black: "\x1b[0;30m".to_string(), 27 | red: "\x1b[0;31m".to_string(), 28 | green: "\x1b[0;32m".to_string(), 29 | orange: "\x1b[0;33m".to_string(), 30 | blue: "\x1b[0;34m".to_string(), 31 | purple: "\x1b[0;35m".to_string(), 32 | cyan: "\x1b[0;36m".to_string(), 33 | light_gray: "\x1b[0;37m".to_string(), 34 | dark_gray: "\x1b[1;30m".to_string(), 35 | light_red: "\x1b[1;31m".to_string(), 36 | light_green: "\x1b[1;32m".to_string(), 37 | yellow: "\x1b[1;33m".to_string(), 38 | light_blue: "\x1b[1;34m".to_string(), 39 | light_purple: "\x1b[1;35m".to_string(), 40 | light_cyan: "\x1b[1;36m".to_string(), 41 | white: "\x1b[1;37m".to_string(), 42 | nc: "\x1b[0m".to_string(), // no_color 43 | clear_screen: "\x1bc".to_string(), 44 | } 45 | } 46 | 47 | pub fn disable(&mut self) { 48 | self.black = "".to_string(); 49 | self.red = "".to_string(); 50 | self.green = "".to_string(); 51 | self.orange = "".to_string(); 52 | self.blue = "".to_string(); 53 | self.purple = "".to_string(); 54 | self.cyan = "".to_string(); 55 | self.light_gray = "".to_string(); 56 | self.dark_gray = "".to_string(); 57 | self.light_red = "".to_string(); 58 | self.light_green = "".to_string(); 59 | self.yellow = "".to_string(); 60 | self.light_blue = "".to_string(); 61 | self.light_purple = "".to_string(); 62 | self.light_cyan = "".to_string(); 63 | self.white = "".to_string(); 64 | self.nc = "".to_string(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/emu/console.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | use std::num::ParseIntError; 3 | 4 | pub struct Console {} 5 | 6 | impl Console { 7 | pub fn new() -> Console { 8 | log::info!("--- console ---"); 9 | Console {} 10 | } 11 | 12 | pub fn print(&self, msg: &str) { 13 | print!("{}", msg); 14 | std::io::stdout().flush().unwrap(); 15 | } 16 | 17 | pub fn cmd(&self) -> String { 18 | let mut line = String::new(); 19 | self.print("=>"); 20 | std::io::stdin().read_line(&mut line).unwrap(); 21 | line = line.replace("\r", ""); // some shells (windows) also add \r thanks Alberto Segura 22 | line.truncate(line.len() - 1); 23 | line.to_lowercase() 24 | } 25 | 26 | pub fn cmd2(&self) -> String { 27 | let mut line = String::new(); 28 | self.print("=>"); 29 | std::io::stdin().read_line(&mut line).unwrap(); 30 | line = line.replace("\r", ""); // some shells (windows) also add \r thanks Alberto Segura 31 | line.truncate(line.len() - 1); 32 | line 33 | } 34 | 35 | pub fn cmd_hex32(&self) -> Result { 36 | let mut x = self.cmd(); 37 | 38 | if x.ends_with('h') { 39 | x = x[0..x.len() - 1].to_string(); 40 | } 41 | if x.starts_with("0x") { 42 | x = x[2..x.len()].to_string(); 43 | } 44 | 45 | return u32::from_str_radix(x.as_str(), 16); 46 | } 47 | 48 | pub fn cmd_hex64(&self) -> Result { 49 | let mut x = self.cmd(); 50 | if x.ends_with('h') { 51 | x = x[0..x.len() - 1].to_string(); 52 | } 53 | if x.starts_with("0x") { 54 | x = x[2..x.len()].to_string(); 55 | } 56 | 57 | return u64::from_str_radix(x.as_str(), 16); 58 | } 59 | 60 | pub fn cmd_num(&self) -> Result { 61 | u64::from_str_radix(self.cmd().as_str(), 10) 62 | } 63 | 64 | /* 65 | pub fn cmd_num(&self) -> Result { 66 | self.cmd().as_str().parse::() 67 | }*/ 68 | 69 | pub fn help(&self) { 70 | log::info!("--- help ---"); 71 | log::info!("q ...................... quit"); 72 | log::info!("cls .................... clear screen"); 73 | log::info!("h ...................... help"); 74 | log::info!("s ...................... stack"); 75 | log::info!("v ...................... vars"); 76 | log::info!("sv ..................... set verbose level 0, 1 or 2"); 77 | log::info!("r ...................... register show all"); 78 | log::info!("r reg .................. show reg"); 79 | log::info!("rc ..................... register change"); 80 | log::info!("f ...................... show all flags"); 81 | log::info!("fc ..................... clear all flags"); 82 | log::info!("fz ..................... toggle flag zero"); 83 | log::info!("fs ..................... toggle flag sign"); 84 | log::info!("c ...................... continue"); 85 | log::info!("b ...................... breakpoint list"); 86 | log::info!("ba ..................... breakpoint on address"); 87 | log::info!("bi ..................... breakpoint on instruction number"); 88 | log::info!("bmr .................... breakpoint on read memory"); 89 | log::info!("bmw .................... breakpoint on write memory"); 90 | log::info!("bmx .................... breakpoint on execute memory"); 91 | log::info!("bcmp ................... break on next cmp or test"); 92 | log::info!("bc ..................... clear breakpoint"); 93 | log::info!("n ...................... next instruction"); 94 | log::info!("eip .................... change eip"); 95 | log::info!("rip .................... change rip"); 96 | log::info!("push ................... push dword to the stack"); 97 | log::info!("pop .................... pop dword from stack"); 98 | log::info!("fpu .................... fpu view"); 99 | log::info!("md5 .................... check the md5 of a memory map"); 100 | log::info!("seh .................... view SEH"); 101 | log::info!("veh .................... view vectored execption pointer"); 102 | log::info!("m ...................... memory maps"); 103 | log::info!("ms ..................... memory filtered by keyword string"); 104 | log::info!("ma ..................... memory allocs"); 105 | log::info!("mc ..................... memory create map"); 106 | log::info!("mn ..................... memory name of an address"); 107 | log::info!("ml ..................... memory load file content to map"); 108 | log::info!("mr ..................... memory read, speficy ie: dword ptr [esi]"); 109 | log::info!( 110 | "mw ..................... memory write, speficy ie: dword ptr [esi] and then: 1af" 111 | ); 112 | log::info!("mwb .................... memory write bytes, input spaced bytes"); 113 | log::info!("md ..................... memory dump"); 114 | log::info!("mrd .................... memory read dwords"); 115 | log::info!("mrq .................... memory read qwords"); 116 | log::info!("mds .................... memory dump string"); 117 | log::info!("mdw .................... memory dump wide string"); 118 | log::info!("mdd .................... memory dump to disk"); 119 | log::info!("mdda ................... memory dump all allocations to disk"); 120 | log::info!("mt ..................... memory test"); 121 | log::info!("ss ..................... search string"); 122 | log::info!("sb ..................... search bytes"); 123 | log::info!("sba .................... search bytes in all the maps"); 124 | log::info!("ssa .................... search string in all the maps"); 125 | log::info!("ll ..................... linked list walk"); 126 | log::info!("d ...................... dissasemble"); 127 | log::info!("dt ..................... dump structure"); 128 | log::info!("enter .................. step into"); 129 | log::info!("tr ..................... trace reg"); 130 | log::info!("trc .................... trace regs clear"); 131 | log::info!("ldr .................... show ldr linked list"); 132 | log::info!("iat .................... find api name in all iat's "); 133 | log::info!("iatx ................... addr to api name"); 134 | log::info!("iatd ................... dump the iat of specific module"); 135 | 136 | //log::info!("o ...................... step over"); 137 | log::info!(""); 138 | log::info!("---"); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/emu/context32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu::fpu::FPU; 2 | use crate::emu::maps::Maps; 3 | use crate::emu::regs64::Regs64; 4 | 5 | pub struct Context32 { 6 | ctx_flags: u32, 7 | dr0: u32, 8 | dr1: u32, 9 | dr2: u32, 10 | dr3: u32, 11 | dr6: u32, 12 | dr7: u32, 13 | fpu: FPU, 14 | seg_gs: u32, 15 | seg_fd: u32, 16 | seg_es: u32, 17 | seg_ds: u32, 18 | edi: u32, // +9c 19 | esi: u32, // +a0 20 | ebx: u32, // +a4 21 | edx: u32, // +a8 22 | ecx: u32, // +ac 23 | eax: u32, // +b0 24 | ebp: u32, // +b4 25 | eip: u32, // +b8 26 | seg_cs: u32, // +bc 27 | eflags: u32, // +c0 28 | esp: u32, // +c4 29 | seg_ss: u32, 30 | } 31 | 32 | impl Context32 { 33 | pub fn new(regs: &Regs64) -> Context32 { 34 | Context32 { 35 | ctx_flags: 0, 36 | dr0: 0, 37 | dr1: 0, 38 | dr2: 0, 39 | dr3: 0, 40 | dr6: 0, 41 | dr7: 0, 42 | fpu: FPU::new(), 43 | seg_gs: 0, 44 | seg_fd: 0, 45 | seg_es: 0, 46 | seg_ds: 0, 47 | edi: regs.get_edi() as u32, 48 | esi: regs.get_esi() as u32, 49 | ebx: regs.get_ebx() as u32, 50 | edx: regs.get_edx() as u32, 51 | ecx: regs.get_ecx() as u32, 52 | eax: regs.get_eax() as u32, 53 | ebp: regs.get_ebp() as u32, 54 | eip: regs.get_eip() as u32, 55 | seg_cs: 0, 56 | eflags: 0, 57 | esp: regs.get_esp() as u32, 58 | seg_ss: 0, 59 | } 60 | } 61 | 62 | pub fn save(&self, addr: u32, maps: &mut Maps) { 63 | maps.write_dword((addr + 4) as u64, self.dr0); 64 | maps.write_dword((addr + 8) as u64, self.dr1); 65 | maps.write_dword((addr + 12) as u64, self.dr2); 66 | maps.write_dword((addr + 16) as u64, self.dr3); 67 | maps.write_dword((addr + 20) as u64, self.dr6); 68 | maps.write_dword((addr + 24) as u64, self.dr7); 69 | 70 | maps.write_dword((addr + 0x9c) as u64, self.edi); 71 | maps.write_dword((addr + 0xa0) as u64, self.esi); 72 | maps.write_dword((addr + 0xa4) as u64, self.ebx); 73 | maps.write_dword((addr + 0xa8) as u64, self.edx); 74 | maps.write_dword((addr + 0xac) as u64, self.ecx); 75 | maps.write_dword((addr + 0xb0) as u64, self.eax); 76 | maps.write_dword((addr + 0xb4) as u64, self.ebp); 77 | maps.write_dword((addr + 0xb8) as u64, self.eip); 78 | maps.write_dword((addr + 0xc4) as u64, self.esp); 79 | } 80 | 81 | pub fn load(&mut self, addr: u32, maps: &mut Maps) { 82 | self.dr0 = maps 83 | .read_dword((addr + 4) as u64) 84 | .expect("cannot read dr0 from ctx"); 85 | self.dr1 = maps 86 | .read_dword((addr + 8) as u64) 87 | .expect("cannot read dr1 from ctx"); 88 | self.dr2 = maps 89 | .read_dword((addr + 12) as u64) 90 | .expect("cannot read dr2 from ctx"); 91 | self.dr3 = maps 92 | .read_dword((addr + 16) as u64) 93 | .expect("cannot read dr3 from ctx"); 94 | self.dr6 = maps 95 | .read_dword((addr + 20) as u64) 96 | .expect("cannot read dr6 from ctx"); 97 | self.dr7 = maps 98 | .read_dword((addr + 24) as u64) 99 | .expect("cannot read dr7 from ctx"); 100 | 101 | self.edi = maps 102 | .read_dword((addr + 0x9c) as u64) 103 | .expect("cannot read edi from ctx"); 104 | self.esi = maps 105 | .read_dword((addr + 0xa0) as u64) 106 | .expect("cannot read esi from ctx"); 107 | self.ebx = maps 108 | .read_dword((addr + 0xa4) as u64) 109 | .expect("cannot read ebx from ctx"); 110 | self.edx = maps 111 | .read_dword((addr + 0xa8) as u64) 112 | .expect("cannot read edx from ctx"); 113 | self.ecx = maps 114 | .read_dword((addr + 0xac) as u64) 115 | .expect("cannot read ecx from ctx"); 116 | self.eax = maps 117 | .read_dword((addr + 0xb0) as u64) 118 | .expect("cannot read eax from ctx"); 119 | self.ebp = maps 120 | .read_dword((addr + 0xb4) as u64) 121 | .expect("cannot read ebp from ctx"); 122 | self.eip = maps 123 | .read_dword((addr + 0xb8) as u64) 124 | .expect("cannot read eip from ctx"); 125 | self.esp = maps 126 | .read_dword((addr + 0xc4) as u64) 127 | .expect("cannot read esp from ctx"); 128 | } 129 | 130 | pub fn sync(&self, regs: &mut Regs64) { 131 | regs.set_eax(self.eax as u64); 132 | regs.set_ebx(self.ebx as u64); 133 | regs.set_ecx(self.ecx as u64); 134 | regs.set_edx(self.edx as u64); 135 | regs.set_esi(self.esi as u64); 136 | regs.set_edi(self.edi as u64); 137 | regs.set_esp(self.esp as u64); 138 | regs.set_ebp(self.ebp as u64); 139 | regs.set_eip(self.eip as u64); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/emu/context64.rs: -------------------------------------------------------------------------------- 1 | use crate::emu::fpu::FPU; 2 | use crate::emu::maps::Maps; 3 | use crate::emu::regs64::Regs64; 4 | 5 | // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context 6 | 7 | pub struct Context64 { 8 | p1_home: u64, 9 | p2_home: u64, 10 | p3_home: u64, 11 | p4_home: u64, 12 | p5_home: u64, 13 | p6_home: u64, 14 | ctx_flags: u32, 15 | mx_csr: u16, 16 | seg_cs: u16, 17 | seg_ds: u16, 18 | seg_es: u16, 19 | seg_fs: u16, 20 | seg_gs: u16, 21 | seg_ss: u16, 22 | eflags: u32, 23 | dr0: u64, 24 | dr1: u64, 25 | dr2: u64, 26 | dr3: u64, 27 | dr6: u64, 28 | dr7: u64, 29 | rax: u64, 30 | rcx: u64, 31 | rdx: u64, 32 | rbx: u64, 33 | rsp: u64, 34 | rbp: u64, 35 | rsi: u64, 36 | rdi: u64, 37 | r8: u64, 38 | r9: u64, 39 | r10: u64, 40 | r11: u64, 41 | r12: u64, 42 | r13: u64, 43 | r14: u64, 44 | r15: u64, 45 | rip: u64, 46 | fpu: FPU, 47 | } 48 | 49 | impl Context64 { 50 | pub fn new(regs: &Regs64) -> Context64 { 51 | Context64 { 52 | p1_home: 0, 53 | p2_home: 0, 54 | p3_home: 0, 55 | p4_home: 0, 56 | p5_home: 0, 57 | p6_home: 0, 58 | ctx_flags: 0, 59 | dr0: 0, 60 | dr1: 0, 61 | dr2: 0, 62 | dr3: 0, 63 | dr6: 0, 64 | dr7: 0, 65 | mx_csr: 0, 66 | seg_fs: 0, 67 | seg_gs: 0, 68 | seg_es: 0, 69 | seg_ds: 0, 70 | seg_cs: 0, 71 | seg_ss: 0, 72 | eflags: 0, 73 | rdi: regs.rdi, 74 | rsi: regs.rsi, 75 | rbx: regs.rbx, 76 | rdx: regs.rdx, 77 | rcx: regs.rcx, 78 | rax: regs.rax, 79 | rbp: regs.rbp, 80 | rip: regs.rip, 81 | rsp: regs.rsp, 82 | r8: regs.r8, 83 | r9: regs.r9, 84 | r10: regs.r10, 85 | r11: regs.r11, 86 | r12: regs.r12, 87 | r13: regs.r13, 88 | r14: regs.r14, 89 | r15: regs.r15, 90 | fpu: FPU::new(), 91 | } 92 | } 93 | 94 | /* 95 | typedef struct _CONTEXT { 96 | DWORD64 P1Home; 0 97 | DWORD64 P2Home; 8 98 | DWORD64 P3Home; 16 99 | DWORD64 P4Home; 24 100 | DWORD64 P5Home; 32 101 | DWORD64 P6Home; 40 102 | DWORD ContextFlags; 48 103 | DWORD MxCsr; 52 104 | WORD SegCs; 56 105 | WORD SegDs; 58 106 | WORD SegEs; 60 107 | WORD SegFs; 62 108 | WORD SegGs; 64 109 | WORD SegSs; 66 110 | DWORD EFlags; 68 111 | DWORD64 Dr0; 72 112 | DWORD64 Dr1; 80 113 | DWORD64 Dr2; 88 114 | DWORD64 Dr3; 96 115 | DWORD64 Dr6; 104 116 | DWORD64 Dr7; 112 117 | DWORD64 Rax; 120 118 | DWORD64 Rcx; 128 119 | DWORD64 Rdx; 136 120 | DWORD64 Rbx; 144 121 | DWORD64 Rsp; 152 122 | DWORD64 Rbp; 160 123 | DWORD64 Rsi; 168 124 | DWORD64 Rdi; 176 125 | DWORD64 R8; 184 126 | DWORD64 R9; 192 127 | DWORD64 R10; 200 128 | DWORD64 R11; 208 129 | DWORD64 R12; 216 130 | DWORD64 R13; 224 131 | DWORD64 R14; 232 132 | DWORD64 R15; 240 133 | DWORD64 Rip; 248 134 | */ 135 | 136 | pub fn save(&self, addr: u64, maps: &mut Maps) { 137 | maps.write_qword(addr + 72, self.dr0); 138 | maps.write_qword(addr + 80, self.dr1); 139 | maps.write_qword(addr + 88, self.dr2); 140 | maps.write_qword(addr + 96, self.dr3); 141 | maps.write_qword(addr + 104, self.dr6); 142 | maps.write_qword(addr + 112, self.dr7); 143 | 144 | maps.write_qword(addr + 120, self.rax); 145 | maps.write_qword(addr + 128, self.rcx); 146 | maps.write_qword(addr + 136, self.rdx); 147 | maps.write_qword(addr + 144, self.rbx); 148 | maps.write_qword(addr + 152, self.rsp); 149 | maps.write_qword(addr + 160, self.rbp); 150 | maps.write_qword(addr + 168, self.rdi); 151 | maps.write_qword(addr + 176, self.rsi); 152 | 153 | maps.write_qword(addr + 184, self.r8); 154 | maps.write_qword(addr + 192, self.r9); 155 | maps.write_qword(addr + 200, self.r10); 156 | maps.write_qword(addr + 208, self.r11); 157 | maps.write_qword(addr + 216, self.r12); 158 | maps.write_qword(addr + 224, self.r13); 159 | maps.write_qword(addr + 232, self.r14); 160 | maps.write_qword(addr + 240, self.r15); 161 | 162 | maps.write_qword(addr + 248, self.rip); 163 | } 164 | 165 | pub fn load(&mut self, addr: u64, maps: &mut Maps) { 166 | self.dr0 = maps 167 | .read_qword(addr + 72) 168 | .expect("cannot read dr0 from ctx"); 169 | self.dr1 = maps 170 | .read_qword(addr + 80) 171 | .expect("cannot read dr1 from ctx"); 172 | self.dr2 = maps 173 | .read_qword(addr + 88) 174 | .expect("cannot read dr2 from ctx"); 175 | self.dr3 = maps 176 | .read_qword(addr + 96) 177 | .expect("cannot read dr3 from ctx"); 178 | self.dr6 = maps 179 | .read_qword(addr + 104) 180 | .expect("cannot read dr6 from ctx"); 181 | self.dr7 = maps 182 | .read_qword(addr + 112) 183 | .expect("cannot read dr7 from ctx"); 184 | 185 | self.rax = maps 186 | .read_qword(addr + 120) 187 | .expect("cannot read rax from ctx"); 188 | self.rcx = maps 189 | .read_qword(addr + 128) 190 | .expect("cannot read rcx from ctx"); 191 | self.rdx = maps 192 | .read_qword(addr + 136) 193 | .expect("cannot read rdx from ctx"); 194 | self.rbx = maps 195 | .read_qword(addr + 144) 196 | .expect("cannot read rbx from ctx"); 197 | self.rsp = maps 198 | .read_qword(addr + 152) 199 | .expect("cannot read rsp from ctx"); 200 | self.rbp = maps 201 | .read_qword(addr + 160) 202 | .expect("cannot read rbp from ctx"); 203 | self.rdi = maps 204 | .read_qword(addr + 168) 205 | .expect("cannot read rdi from ctx"); 206 | self.rsi = maps 207 | .read_qword(addr + 176) 208 | .expect("cannot read rsi from ctx"); 209 | 210 | self.r8 = maps 211 | .read_qword(addr + 184) 212 | .expect("cannot read r8 from ctx"); 213 | self.r9 = maps 214 | .read_qword(addr + 192) 215 | .expect("cannot read r9 from ctx"); 216 | self.r10 = maps 217 | .read_qword(addr + 200) 218 | .expect("cannot read r10 from ctx"); 219 | self.r11 = maps 220 | .read_qword(addr + 208) 221 | .expect("cannot read r11 from ctx"); 222 | self.r12 = maps 223 | .read_qword(addr + 216) 224 | .expect("cannot read r12 from ctx"); 225 | self.r13 = maps 226 | .read_qword(addr + 224) 227 | .expect("cannot read r13 from ctx"); 228 | self.r14 = maps 229 | .read_qword(addr + 232) 230 | .expect("cannot read r14 from ctx"); 231 | self.r15 = maps 232 | .read_qword(addr + 240) 233 | .expect("cannot read r15 from ctx"); 234 | 235 | self.rip = maps 236 | .read_qword(addr + 248) 237 | .expect("cannot read rip from ctx"); 238 | } 239 | 240 | pub fn sync(&self, regs: &mut Regs64) { 241 | regs.rax = self.rax; 242 | regs.rbx = self.rbx; 243 | regs.rcx = self.rcx; 244 | regs.rdx = self.rdx; 245 | regs.rsi = self.rsi; 246 | regs.rdi = self.rdi; 247 | regs.rsp = self.rsp; 248 | regs.rbp = self.rbp; 249 | regs.rip = self.rip; 250 | 251 | regs.r8 = self.r8; 252 | regs.r9 = self.r9; 253 | regs.r10 = self.r10; 254 | regs.r11 = self.r11; 255 | regs.r12 = self.r12; 256 | regs.r13 = self.r13; 257 | regs.r14 = self.r14; 258 | regs.r15 = self.r15; 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/emu/eflags.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct Eflags { 3 | pub rf: bool, 4 | pub vm: bool, 5 | pub ac: bool, 6 | pub vif: bool, 7 | pub id: bool, 8 | } 9 | 10 | impl Eflags { 11 | pub fn new() -> Eflags { 12 | Eflags { 13 | rf: false, 14 | vm: false, 15 | ac: false, 16 | vif: false, 17 | id: false, 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/emu/elf32.rs: -------------------------------------------------------------------------------- 1 | use super::err::ScemuError; 2 | use crate::emu::maps::Maps; 3 | use super::maps::mem64::Mem64; 4 | use super::constants; 5 | use std::fs::File; 6 | use std::io::Read; 7 | 8 | macro_rules! read_u8 { 9 | ($raw:expr, $off:expr) => { 10 | $raw[$off] 11 | }; 12 | } 13 | 14 | macro_rules! read_u16_le { 15 | ($raw:expr, $off:expr) => { 16 | (($raw[$off + 1] as u16) << 8) | ($raw[$off] as u16) 17 | }; 18 | } 19 | 20 | macro_rules! read_u32_le { 21 | ($raw:expr, $off:expr) => { 22 | (($raw[$off + 3] as u32) << 24) 23 | | (($raw[$off + 2] as u32) << 16) 24 | | (($raw[$off + 1] as u32) << 8) 25 | | ($raw[$off] as u32) 26 | }; 27 | } 28 | 29 | 30 | 31 | pub const EI_NIDENT:usize = 16; 32 | pub const ELFCLASS32:u8 = 0x01; 33 | 34 | #[derive(Debug)] 35 | pub struct Elf32 { 36 | pub bin: Vec, 37 | pub elf_hdr: Elf32Ehdr, 38 | pub elf_phdr: Vec, 39 | pub elf_shdr: Vec, 40 | } 41 | 42 | impl Elf32 { 43 | pub fn parse(filename: &str) -> Result { 44 | let mut mem: Mem64 = Mem64::new(); 45 | if !mem.load(&filename) { 46 | return Err(ScemuError::new("cannot open elf binary")); 47 | } 48 | let bin = mem.get_mem(); 49 | 50 | let ehdr:Elf32Ehdr = Elf32Ehdr::parse(&bin); 51 | 52 | Ok(Elf32 { 53 | bin: bin, 54 | elf_hdr: ehdr, 55 | elf_phdr: Vec::new(), 56 | elf_shdr: Vec::new(), 57 | }) 58 | } 59 | 60 | pub fn load(&mut self, maps: &mut Maps) { 61 | maps.clear(); 62 | let mut off = self.elf_hdr.e_phoff as usize; 63 | 64 | for _ in 0..self.elf_hdr.e_phnum { 65 | let phdr:Elf32Phdr = Elf32Phdr::parse(&self.bin, off); 66 | self.elf_phdr.push(phdr); 67 | off += self.elf_hdr.e_phentsize as usize; 68 | } 69 | 70 | off = self.elf_hdr.e_shoff as usize; 71 | 72 | for _ in 0..self.elf_hdr.e_shnum { 73 | let shdr:Elf32Shdr = Elf32Shdr::parse(&self.bin, off); 74 | self.elf_shdr.push(shdr); 75 | off += self.elf_hdr.e_shentsize as usize; 76 | } 77 | 78 | for phdr in &self.elf_phdr { 79 | if phdr.p_type == constants::PT_LOAD { 80 | 81 | /* 82 | for shdr in &self.elf_shdr { 83 | if shdr.sh_addr >= phdr.p_vaddr && 84 | shdr.sh_addr < phdr.p_vaddr+phdr.p_memsz { 85 | let end = self.bin.iter().skip(off) 86 | .position(|&x| x == 0x00).unwrap_or(0) + off; 87 | let name = std::str::from_utf8(&self.bin[off..end]).unwrap(); 88 | log::info!("la seccion {} es pt_load", &name); 89 | 90 | } 91 | }*/ 92 | 93 | let mem = maps.create_map(&format!("code"), phdr.p_vaddr.into(), phdr.p_memsz.into()).expect("cannot create code map from load_programs elf32"); 94 | if phdr.p_filesz >phdr.p_memsz { 95 | log::info!("p_filesz > p_memsz bigger in file than in memory."); 96 | } 97 | log::info!("segment {} - {}", phdr.p_offset, (phdr.p_offset+phdr.p_filesz)); 98 | let segment = &self.bin[phdr.p_offset as usize.. 99 | (phdr.p_offset + phdr.p_filesz) as usize]; 100 | mem.write_bytes(phdr.p_vaddr.into(), segment); 101 | } 102 | } 103 | 104 | } 105 | 106 | pub fn is_elf32(filename:&str) -> bool { 107 | //log::info!("checking if elf32: {}", filename); 108 | let mut fd = File::open(filename).expect("file not found"); 109 | let mut raw = vec![0u8; 5]; 110 | fd.read_exact(&mut raw).expect("couldnt read the file"); 111 | 112 | if raw[0] == 0x7f && 113 | raw[1] == b'E' && 114 | raw[2] == b'L' && 115 | raw[3] == b'F' && 116 | raw[4] == ELFCLASS32 { 117 | return true; 118 | } 119 | false 120 | } 121 | } 122 | 123 | #[derive(Debug)] 124 | pub struct Elf32Ehdr { 125 | pub e_ident: [u8; EI_NIDENT], 126 | pub e_type: u16, 127 | pub e_machine: u16, 128 | pub e_version: u32, 129 | pub e_entry: u32, 130 | pub e_phoff: u32, 131 | pub e_shoff: u32, 132 | pub e_flags: u32, 133 | pub e_ehsize: u16, 134 | pub e_phentsize: u16, 135 | pub e_phnum: u16, 136 | pub e_shentsize: u16, 137 | pub e_shnum: u16, 138 | pub e_shstrndx: u16, 139 | } 140 | 141 | impl Elf32Ehdr { 142 | pub fn new() -> Elf32Ehdr { 143 | Elf32Ehdr { 144 | e_ident: [0; EI_NIDENT], 145 | e_type: 0, 146 | e_machine: 0, 147 | e_version: 0, 148 | e_entry: 0, 149 | e_phoff: 0, 150 | e_shoff: 0, 151 | e_flags: 0, 152 | e_ehsize: 0, 153 | e_phentsize: 0, 154 | e_phnum: 0, 155 | e_shentsize: 0, 156 | e_shnum: 0, 157 | e_shstrndx: 0, 158 | } 159 | } 160 | 161 | pub fn parse(bin: &[u8]) -> Elf32Ehdr { 162 | let off = EI_NIDENT as u64; 163 | Elf32Ehdr { 164 | e_ident: [ 165 | read_u8!(bin, 0), 166 | read_u8!(bin, 1), 167 | read_u8!(bin, 2), 168 | read_u8!(bin, 3), 169 | read_u8!(bin, 4), 170 | read_u8!(bin, 5), 171 | read_u8!(bin, 6), 172 | read_u8!(bin, 7), 173 | read_u8!(bin, 8), 174 | read_u8!(bin, 9), 175 | read_u8!(bin, 10), 176 | read_u8!(bin, 11), 177 | read_u8!(bin, 12), 178 | read_u8!(bin, 13), 179 | read_u8!(bin, 14), 180 | read_u8!(bin, 15), 181 | ], 182 | e_type: read_u16_le!(bin, 16), 183 | e_machine: read_u16_le!(bin, 18), 184 | e_version: read_u32_le!(bin, 20), 185 | e_entry: read_u32_le!(bin, 24), 186 | e_phoff: read_u32_le!(bin, 28), 187 | e_shoff: read_u32_le!(bin, 32), 188 | e_flags: read_u32_le!(bin, 36), 189 | e_ehsize: read_u16_le!(bin, 40), 190 | e_phentsize: read_u16_le!(bin, 42), 191 | e_phnum: read_u16_le!(bin, 44), 192 | e_shentsize: read_u16_le!(bin, 46), 193 | e_shnum: read_u16_le!(bin, 48), 194 | e_shstrndx: read_u16_le!(bin, 50), 195 | } 196 | } 197 | } 198 | 199 | #[derive(Debug)] 200 | pub struct Elf32Phdr { 201 | pub p_type: u32, 202 | pub p_offset: u32, 203 | pub p_vaddr: u32, 204 | pub p_paddr: u32, 205 | pub p_filesz: u32, 206 | pub p_memsz: u32, 207 | pub p_flags: u32, 208 | pub p_align: u32, 209 | } 210 | 211 | impl Elf32Phdr { 212 | pub fn parse(bin: &[u8], phoff: usize) -> Elf32Phdr { 213 | Elf32Phdr { 214 | p_type: read_u32_le!(bin, phoff), 215 | p_offset: read_u32_le!(bin, phoff+4), 216 | p_vaddr: read_u32_le!(bin, phoff+8), 217 | p_paddr: read_u32_le!(bin, phoff+12), 218 | p_filesz: read_u32_le!(bin, phoff+16), 219 | p_memsz: read_u32_le!(bin, phoff+20), 220 | p_flags: read_u32_le!(bin, phoff+24), 221 | p_align: read_u32_le!(bin, phoff+28), 222 | } 223 | } 224 | } 225 | 226 | #[derive(Debug)] 227 | pub struct Elf32Shdr { 228 | pub sh_name: u32, 229 | pub sh_type: u32, 230 | pub sh_flags: u32, 231 | pub sh_addr: u32, 232 | pub sh_offset: u32, 233 | pub sh_size: u32, 234 | pub sh_link: u32, 235 | pub sh_info: u32, 236 | pub sh_addralign: u32, 237 | pub sh_entsize: u32, 238 | } 239 | 240 | impl Elf32Shdr { 241 | pub fn parse(bin: &[u8], shoff: usize) -> Elf32Shdr { 242 | Elf32Shdr { 243 | sh_name: read_u32_le!(bin, shoff), 244 | sh_type: read_u32_le!(bin, shoff+4), 245 | sh_flags: read_u32_le!(bin, shoff+8), 246 | sh_addr: read_u32_le!(bin, shoff+12), 247 | sh_offset: read_u32_le!(bin, shoff+16), 248 | sh_size: read_u32_le!(bin, shoff+20), 249 | sh_link: read_u32_le!(bin, shoff+24), 250 | sh_info: read_u32_le!(bin, shoff+28), 251 | sh_addralign: read_u32_le!(bin, shoff+32), 252 | sh_entsize: read_u32_le!(bin, 36), 253 | } 254 | } 255 | } 256 | 257 | 258 | -------------------------------------------------------------------------------- /src/emu/endpoint.rs: -------------------------------------------------------------------------------- 1 | /* 2 | TODO: 3 | - support multiple sockets 4 | - support post 5 | - wide apis 6 | */ 7 | 8 | extern crate attohttpc; 9 | 10 | use attohttpc::header; 11 | use attohttpc::RequestBuilder; 12 | use lazy_static::lazy_static; 13 | use std::collections::HashMap; 14 | use std::io::Read; 15 | use std::io::Write; 16 | use std::net::Shutdown; 17 | use std::net::TcpStream; 18 | use std::sync::Mutex; 19 | 20 | lazy_static! { 21 | static ref STREAM: Mutex> = Mutex::new(Vec::new()); 22 | static ref HTTP_HDRS: Mutex> = Mutex::new(HashMap::new()); 23 | static ref HTTP_SERVER: Mutex = Mutex::new(String::new()); 24 | static ref HTTP_PORT: Mutex = Mutex::new(0); 25 | static ref HTTP_PATH: Mutex = Mutex::new(String::new()); 26 | static ref HTTP_SSL: Mutex = Mutex::new(false); 27 | static ref HTTP_METHOD: Mutex = Mutex::new(String::new()); 28 | static ref HTTP_DATA: Mutex> = Mutex::new(Vec::new()); 29 | } 30 | 31 | pub fn warning() { 32 | print!("/!\\ is your VPN or Tor ready (y/n)? "); 33 | std::io::stdout().flush().unwrap(); 34 | 35 | let mut answer = String::new(); 36 | std::io::stdin().read_line(&mut answer).unwrap(); 37 | answer = answer.replace("\r", ""); // some shells (windows) also add \r thanks Alberto Segura 38 | answer.truncate(answer.len() - 1); 39 | let lanswer = answer.to_lowercase(); 40 | if lanswer != "y" && lanswer != "yes" { 41 | std::process::exit(1); 42 | } 43 | } 44 | 45 | pub fn sock_connect(host: &str, port: u16) -> bool { 46 | let mut stream = STREAM.lock().unwrap(); 47 | log::info!("\tconnecting to {}:{}...", host, port); 48 | stream.push(match TcpStream::connect((host, port)) { 49 | Ok(s) => s, 50 | Err(_) => { 51 | return false; 52 | } 53 | }); 54 | log::info!("\tconnected!"); 55 | return true; 56 | } 57 | 58 | pub fn sock_send(buffer: &[u8]) -> usize { 59 | let mut stream = STREAM.lock().unwrap(); 60 | let n = match stream[0].write(buffer) { 61 | Ok(w) => w, 62 | Err(_) => 0, 63 | }; 64 | return n; 65 | } 66 | 67 | pub fn sock_recv(buffer: &mut [u8]) -> usize { 68 | let mut stream = STREAM.lock().unwrap(); 69 | let n = match stream[0].read(buffer) { 70 | Ok(r) => r, 71 | Err(_) => 0, 72 | }; 73 | return n; 74 | } 75 | 76 | pub fn sock_close() { 77 | let mut stream = STREAM.lock().unwrap(); 78 | match stream[0].shutdown(Shutdown::Both) { 79 | Ok(_) => {} 80 | Err(_) => {} 81 | } 82 | stream.clear(); 83 | } 84 | 85 | pub fn http_set_method(meth: &str) { 86 | let mut method = HTTP_METHOD.lock().unwrap(); 87 | *method = meth.to_string().to_lowercase(); 88 | } 89 | 90 | pub fn http_set_serverport(host: &str, port: u16) { 91 | let mut mhost = HTTP_SERVER.lock().unwrap(); 92 | *mhost = host.to_string(); 93 | 94 | let mut mport = HTTP_PORT.lock().unwrap(); 95 | *mport = port; 96 | } 97 | 98 | pub fn http_set_headers(key: &str, value: &str) { 99 | let mut headers = HTTP_HDRS.lock().unwrap(); 100 | headers.insert( 101 | key.to_string().replace("\r", "").replace("\n", ""), 102 | value.to_string().replace("\r", "").replace("\n", ""), 103 | ); 104 | } 105 | 106 | pub fn http_set_headers_str(hdrs: &str) { 107 | let mut headers = HTTP_HDRS.lock().unwrap(); 108 | 109 | let lines: Vec<&str> = hdrs.split("\n").collect(); 110 | for l in lines.iter() { 111 | let cols: Vec<&str> = l.split(": ").collect(); 112 | if cols.len() == 2 { 113 | headers.insert( 114 | cols[0].to_string().replace("\r", "").replace("\n", ""), 115 | cols[1].to_string().replace("\r", "").replace("\n", ""), 116 | ); 117 | } 118 | } 119 | } 120 | 121 | pub fn http_set_path(ppath: &str) { 122 | let mut path = HTTP_PATH.lock().unwrap(); 123 | *path = ppath.to_string(); 124 | } 125 | 126 | pub fn http_set_ssl() { 127 | let mut ssl = HTTP_SSL.lock().unwrap(); 128 | *ssl = true; 129 | } 130 | 131 | pub fn http_send_request() { 132 | let host = HTTP_SERVER.lock().unwrap(); 133 | let port = HTTP_PORT.lock().unwrap(); 134 | let path = HTTP_PATH.lock().unwrap(); 135 | let https = HTTP_SSL.lock().unwrap(); 136 | let hdrs = HTTP_HDRS.lock().unwrap(); 137 | let method = HTTP_METHOD.lock().unwrap(); 138 | let mut data = HTTP_DATA.lock().unwrap(); 139 | 140 | let url: String; 141 | 142 | if *https { 143 | url = format!("https://{}:{}{}", host, port, path); 144 | } else { 145 | url = format!("http://{}:{}{}", host, port, path); 146 | } 147 | 148 | log::info!("\tconnecting to url: {}", url); 149 | 150 | let mut req: RequestBuilder = match method.as_str() { 151 | "get" => attohttpc::get(url), 152 | "post" => attohttpc::post(url), 153 | "head" => attohttpc::head(url), 154 | "delete" => attohttpc::delete(url), 155 | "options" => attohttpc::options(url), 156 | "patch" => attohttpc::patch(url), 157 | "trace" => attohttpc::trace(url), 158 | _ => { 159 | log::info!("\tweird method."); 160 | return; 161 | } 162 | }; 163 | 164 | req = req.danger_accept_invalid_hostnames(true); 165 | req = req.danger_accept_invalid_certs(true); 166 | 167 | for k in hdrs.keys() { 168 | let key = k.clone(); 169 | let v = &hdrs[&key]; 170 | let hn: header::HeaderName = 171 | match header::HeaderName::from_bytes(&key.to_lowercase().as_bytes()) { 172 | Ok(h) => h, 173 | Err(e) => { 174 | log::info!("\terror in header {} err: {}", &key, e); 175 | return; 176 | } 177 | }; 178 | //log::info!("\tadding header: `{}` value: `{}`", &key, &v); 179 | req = req 180 | .try_header_append::(hn, &v) 181 | .expect("cannot add header"); 182 | } 183 | 184 | let resp = match req.send() { 185 | Ok(r) => r, 186 | Err(_) => { 187 | log::info!("\tCannot connect."); 188 | return; 189 | } 190 | }; 191 | 192 | if resp.is_success() { 193 | *data = resp.bytes().expect("error receiving data"); 194 | log::info!("\t{} bytes downloaded", data.len()); 195 | } else { 196 | log::info!("\tURL not Ok."); 197 | } 198 | } 199 | 200 | pub fn http_read_data() -> Vec { 201 | let mut data = HTTP_DATA.lock().unwrap(); 202 | let r = &*data.clone(); 203 | data.clear(); 204 | return r.to_vec(); 205 | } 206 | -------------------------------------------------------------------------------- /src/emu/err.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | #[derive(Debug)] 4 | pub struct ScemuError { 5 | pub message: String, 6 | } 7 | 8 | impl ScemuError { 9 | pub fn new(message: &str) -> ScemuError { 10 | ScemuError { 11 | message: message.to_string(), 12 | } 13 | } 14 | } 15 | 16 | impl std::fmt::Display for ScemuError { 17 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 18 | write!(f, "SCEMU Error: {}", self.message) 19 | } 20 | } 21 | 22 | impl Error for ScemuError {} 23 | 24 | -------------------------------------------------------------------------------- /src/emu/exception.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::context32::Context32; 3 | use crate::emu::context64::Context64; 4 | 5 | pub fn enter(emu: &mut emu::Emu) { 6 | if emu.cfg.is_64bits { 7 | enter64(emu); 8 | } else { 9 | enter32(emu); 10 | } 11 | } 12 | 13 | pub fn exit(emu: &mut emu::Emu) { 14 | if emu.cfg.is_64bits { 15 | exit64(emu); 16 | } else { 17 | exit32(emu); 18 | } 19 | } 20 | 21 | pub fn enter32(emu: &mut emu::Emu) { 22 | emu.stack_push32(0x10f00); 23 | emu.stack_push32(emu.regs.get_eip() as u32); 24 | 25 | emu.eh_ctx = 0x10f08; 26 | emu.maps.write_dword(0x10f04, emu.eh_ctx); 27 | let ctx = Context32::new(&emu.regs); 28 | ctx.save(emu.eh_ctx, &mut emu.maps); 29 | } 30 | 31 | pub fn exit32(emu: &mut emu::Emu) { 32 | let mut ctx = Context32::new(&emu.regs); 33 | ctx.load(emu.eh_ctx, &mut emu.maps); 34 | ctx.sync(&mut emu.regs); 35 | emu.eh_ctx = 0; 36 | emu.force_reload = true; 37 | } 38 | 39 | pub fn enter64(emu: &mut emu::Emu) { 40 | emu.stack_push64(0x10f00); 41 | emu.stack_push64(emu.regs.rip); 42 | 43 | emu.eh_ctx = 0x10f08; 44 | emu.maps.write_qword(0x10f04, emu.eh_ctx as u64); 45 | let ctx = Context64::new(&emu.regs); 46 | ctx.save(emu.eh_ctx as u64, &mut emu.maps); 47 | } 48 | 49 | pub fn exit64(emu: &mut emu::Emu) { 50 | let mut ctx = Context64::new(&emu.regs); 51 | ctx.load(emu.eh_ctx as u64, &mut emu.maps); 52 | ctx.sync(&mut emu.regs); 53 | emu.eh_ctx = 0; 54 | emu.force_reload = true; 55 | } 56 | -------------------------------------------------------------------------------- /src/emu/fpu.rs: -------------------------------------------------------------------------------- 1 | use iced_x86::Register; 2 | 3 | #[derive(Clone)] 4 | pub struct FPU { 5 | st: Vec, 6 | st_depth: u8, 7 | tag: u16, 8 | pub stat: u16, 9 | ctrl: u16, 10 | ip: u64, 11 | err_off: u32, 12 | err_sel: u32, 13 | code_segment: u16, 14 | data_segment: u16, 15 | operand_ptr: u64, 16 | reserved: [u8; 14], 17 | reserved2: [u8; 96], 18 | xmm: [u64; 16], 19 | top: i8, 20 | pub f_c0: bool, // overflow 21 | pub f_c1: bool, // underflow 22 | pub f_c2: bool, // div by zero 23 | pub f_c3: bool, // precission 24 | pub f_c4: bool, // stack fault 25 | pub mxcsr: u32, 26 | } 27 | 28 | impl FPU { 29 | pub fn new() -> FPU { 30 | FPU { 31 | st: vec![0.0; 8], 32 | st_depth: 0, 33 | tag: 0xffff, 34 | stat: 0, 35 | ctrl: 0x027f, 36 | ip: 0, 37 | err_off: 0, 38 | err_sel: 0, 39 | code_segment: 0, 40 | data_segment: 0, 41 | operand_ptr: 0, 42 | reserved: [0; 14], 43 | reserved2: [0; 96], 44 | xmm: [0; 16], 45 | top: 0, 46 | f_c0: false, // overflow 47 | f_c1: false, // underflow 48 | f_c2: false, // div by zero 49 | f_c3: false, // precision 50 | f_c4: false, // stack fault 51 | mxcsr: 0, 52 | } 53 | } 54 | 55 | pub fn clear(&mut self) { 56 | self.st.clear(); 57 | self.st_depth = 0; 58 | self.st = vec![0.0; 8]; 59 | self.tag = 0xffff; 60 | self.stat = 0; 61 | self.ctrl = 0x037f; 62 | self.ip = 0; 63 | self.err_off = 0; 64 | self.err_sel = 0; 65 | self.code_segment = 0; 66 | self.data_segment = 0; 67 | self.operand_ptr = 0; 68 | self.reserved = [0; 14]; 69 | self.reserved2 = [0; 96]; 70 | self.xmm = [0; 16]; 71 | } 72 | 73 | pub fn set_ctrl(&mut self, ctrl: u16) { 74 | self.ctrl = ctrl; 75 | } 76 | 77 | pub fn get_ctrl(&self) -> u16 { 78 | return self.ctrl; 79 | } 80 | 81 | pub fn set_ip(&mut self, ip: u64) { 82 | self.ip = ip; 83 | } 84 | 85 | pub fn inc_top(&mut self) { 86 | self.top = (self.top + 1) % 8; 87 | } 88 | 89 | pub fn dec_top(&mut self) { 90 | if self.top == 0 { 91 | self.top = 7; 92 | } else { 93 | self.top -= 1; 94 | } 95 | } 96 | 97 | pub fn get_env32(&self) -> Vec { 98 | let mut r: Vec = Vec::new(); 99 | let mut r1: u32 = self.tag as u32; 100 | r1 <<= 16; 101 | r1 += self.ctrl as u32; 102 | r.push(r1); 103 | r.push(0xffff0000); 104 | r.push(0xffffffff); 105 | r.push(self.ip as u32); 106 | r 107 | } 108 | 109 | pub fn get_env64(&self) -> Vec { 110 | let mut r: Vec = Vec::new(); 111 | let mut r1: u64 = self.tag as u64; 112 | r1 <<= 16; 113 | r1 += self.ctrl as u64; 114 | r.push(r1); 115 | r.push(0xffff0000); 116 | r.push(0xffffffff); 117 | r.push(self.ip); 118 | r 119 | } 120 | 121 | pub fn print(&self) { 122 | log::info!("---- fpu ----"); 123 | for i in 0..self.st.len() { 124 | log::info!("st({}): {}", i, self.st[i]); 125 | } 126 | 127 | log::info!("stat: 0x{:x}", self.stat); 128 | log::info!("ctrl: 0x{:x}", self.ctrl); 129 | log::info!("eip: 0x{:x}", self.ip); 130 | 131 | log::info!("--------"); 132 | } 133 | 134 | pub fn set_st(&mut self, i: usize, value: f64) { 135 | self.st[i] = value; 136 | } 137 | 138 | pub fn get_st(&mut self, i: usize) -> f64 { 139 | if self.st_depth == 0 { 140 | self.f_c4 = true; 141 | } else { 142 | self.f_c4 = false; 143 | } 144 | return self.st[i].clone(); 145 | } 146 | 147 | pub fn xchg_st(&mut self, i: usize) { 148 | let tmp = self.st[0]; 149 | self.st[0] = self.st[i]; 150 | self.st[i] = tmp; 151 | } 152 | 153 | pub fn clear_st(&mut self, i: usize) { 154 | self.st[i] = 0.0; 155 | } 156 | 157 | pub fn move_to_st0(&mut self, i: usize) { 158 | self.st[0] = self.st[i]; 159 | } 160 | 161 | pub fn add_to_st0(&mut self, i: usize) { 162 | self.st[0] = self.st[0] + self.st[i]; 163 | } 164 | 165 | pub fn add(&mut self, i: usize, j: usize) { 166 | self.st[i] = self.st[i] + self.st[j]; 167 | } 168 | 169 | pub fn push(&mut self, value: f64) { 170 | if self.st_depth >= 8 { 171 | self.f_c0 = true; // overflow 172 | } else { 173 | self.st_depth += 1; 174 | self.f_c0 = false; 175 | } 176 | self.st[7] = self.st[6]; 177 | self.st[6] = self.st[5]; 178 | self.st[5] = self.st[4]; 179 | self.st[4] = self.st[3]; 180 | self.st[3] = self.st[2]; 181 | self.st[2] = self.st[1]; 182 | self.st[1] = self.st[0]; 183 | self.st[0] = value; 184 | } 185 | 186 | pub fn pop(&mut self) -> f64 { 187 | if self.st_depth == 0 { 188 | self.f_c1 = true; 189 | } else { 190 | self.st_depth -= 1; 191 | self.f_c1 = false; 192 | } 193 | let result = self.st[0]; 194 | self.st[0] = self.st[1]; 195 | self.st[1] = self.st[2]; 196 | self.st[2] = self.st[3]; 197 | self.st[3] = self.st[4]; 198 | self.st[4] = self.st[5]; 199 | self.st[5] = self.st[6]; 200 | self.st[6] = self.st[7]; 201 | self.st[7] = 0.0; 202 | return result; 203 | } 204 | 205 | pub fn fyl2x(&mut self) { 206 | self.st[1] = self.st[1] * self.st[0].log2(); 207 | self.pop(); 208 | } 209 | 210 | pub fn fyl2xp1(&mut self) { 211 | self.st[1] = self.st[1] * (self.st[0].log2() + 1.0); 212 | self.pop(); 213 | } 214 | 215 | pub fn check_pending_exceptions(self) {} 216 | 217 | pub fn set_streg(&mut self, reg: Register, value: f64) { 218 | match reg { 219 | Register::ST0 => self.st[0] = value, 220 | Register::ST1 => self.st[1] = value, 221 | Register::ST2 => self.st[2] = value, 222 | Register::ST3 => self.st[3] = value, 223 | Register::ST4 => self.st[4] = value, 224 | Register::ST5 => self.st[5] = value, 225 | Register::ST6 => self.st[6] = value, 226 | Register::ST7 => self.st[7] = value, 227 | _ => unreachable!(), 228 | } 229 | } 230 | 231 | pub fn frexp(&self, value: f64) -> (f64, i32) { 232 | if value == 0.0 { 233 | (0.0, 0) 234 | } else { 235 | let exponent = value.abs().log2().floor() as i32 + 1; 236 | let mantissa = value / (2f64.powi(exponent)); 237 | 238 | (mantissa, exponent) 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/emu/hook.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use iced_x86::Instruction; 3 | 4 | 5 | // return: false will ignore interrupt handling like 0x80 -> linux 6 | type TypeHookOnInterrupt = fn(emu: &mut emu::Emu, ip_addr: u64, interrupt: u64) -> bool; 7 | // return: allow handle exception? 8 | type TypeHookOnException = fn(emu: &mut emu::Emu, ip_addr: u64) -> bool; 9 | // memory read is pre-read you can modify the value that is going to be read. 10 | type TypeHookOnMemoryRead = fn(emu: &mut emu::Emu, ip_addr: u64, mem_addr: u64, sz: u32); 11 | // the memory write is pre but you can change the value is going to be written. 12 | type TypeHookOnMemoryWrite = 13 | fn(emu: &mut emu::Emu, ip_addr: u64, mem_addr: u64, sz: u32, value: u128) -> u128; 14 | type TypeHookOnPreInstruction = fn(emu: &mut emu::Emu, ip_addr: u64, ins: &Instruction, sz: usize); 15 | type TypeHookOnPostInstruction = 16 | fn(emu: &mut emu::Emu, ip_addr: u64, ins: &Instruction, sz: usize, emu_ok: bool); 17 | type TypeHookOnWinApiCall = fn(emu: &mut emu::Emu, ip_addr: u64, called_addr: u64) -> bool; 18 | 19 | 20 | 21 | pub struct Hook { 22 | pub hook_on_interrupt: Option, 23 | pub hook_on_exception: Option, 24 | pub hook_on_memory_read: Option, 25 | pub hook_on_memory_write: Option, 26 | pub hook_on_pre_instruction: Option, 27 | pub hook_on_post_instruction: Option, 28 | pub hook_on_winapi_call: Option, 29 | } 30 | 31 | impl Hook { 32 | pub fn new() -> Hook { 33 | Hook { 34 | hook_on_interrupt: None, 35 | hook_on_exception: None, 36 | hook_on_memory_read: None, 37 | hook_on_memory_write: None, 38 | hook_on_pre_instruction: None, 39 | hook_on_post_instruction: None, 40 | hook_on_winapi_call: None, 41 | } 42 | } 43 | 44 | pub fn on_interrupt(&mut self, hook: TypeHookOnInterrupt) { 45 | self.hook_on_interrupt = Some(hook); 46 | } 47 | 48 | pub fn disable_interrupt(&mut self) { 49 | self.hook_on_interrupt = None; 50 | } 51 | 52 | pub fn on_exception(&mut self, hook: TypeHookOnException) { 53 | self.hook_on_exception = Some(hook); 54 | } 55 | 56 | pub fn disable_exception(&mut self) { 57 | self.hook_on_exception = None; 58 | } 59 | 60 | pub fn on_memory_read(&mut self, hook: TypeHookOnMemoryRead) { 61 | self.hook_on_memory_read = Some(hook); 62 | } 63 | 64 | pub fn disable_memory_read(&mut self) { 65 | self.hook_on_memory_read = None; 66 | } 67 | 68 | pub fn on_memory_write(&mut self, hook: TypeHookOnMemoryWrite) { 69 | self.hook_on_memory_write = Some(hook); 70 | } 71 | 72 | pub fn disable_memory_write(&mut self) { 73 | self.hook_on_memory_write = None; 74 | } 75 | 76 | pub fn on_pre_instruction(&mut self, hook: TypeHookOnPreInstruction) { 77 | self.hook_on_pre_instruction = Some(hook); 78 | } 79 | 80 | pub fn disable_pre_instruction(&mut self) { 81 | self.hook_on_pre_instruction = None; 82 | } 83 | 84 | pub fn on_post_instruction(&mut self, hook: TypeHookOnPostInstruction) { 85 | self.hook_on_post_instruction = Some(hook); 86 | } 87 | 88 | pub fn disable_post_instruction(&mut self) { 89 | self.hook_on_post_instruction = None; 90 | } 91 | 92 | pub fn on_winapi_call(&mut self, hook: TypeHookOnWinApiCall) { 93 | self.hook_on_winapi_call = Some(hook); 94 | } 95 | 96 | pub fn disable_winapi_call(&mut self) { 97 | self.hook_on_winapi_call = None; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/emu/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | 3 | macro_rules! popn { 4 | ($emu:expr, $n:expr) => { 5 | for _ in 0..$n { 6 | $emu.stack_pop(false); 7 | } 8 | }; 9 | } 10 | 11 | macro_rules! stack_param { 12 | ($emu:expr, $num:expr, $msg:expr) => ( 13 | $emu.read_dword($emu.regs.esp+($num*4)).expect($msg); 14 | ) 15 | } 16 | 17 | macro_rules! get_ip { 18 | ($emu:expr, $ptr:expr) => ( 19 | let ip = $emu.maps.read_dword($ptr+4).expect("cannot read the ip"); 20 | format!("{}.{}.{}.{}", ip&0xff, (ip&0xff00)>>8, (ip&0xff0000)>>16, (ip&0xff000000)>>24); 21 | ) 22 | } 23 | 24 | macro_rules! read_u8 { 25 | ($raw:expr, $off:expr) => { 26 | $raw[$off] 27 | }; 28 | } 29 | 30 | macro_rules! read_u16_le { 31 | ($raw:expr, $off:expr) => { 32 | (($raw[$off + 1] as u16) << 8) | ($raw[$off] as u16) 33 | }; 34 | } 35 | 36 | macro_rules! read_u32_le { 37 | ($raw:expr, $off:expr) => { 38 | (($raw[$off + 3] as u32) << 24) 39 | | (($raw[$off + 2] as u32) << 16) 40 | | (($raw[$off + 1] as u32) << 8) 41 | | ($raw[$off] as u32) 42 | }; 43 | } 44 | 45 | macro_rules! write_u32_le { 46 | ($raw:expr, $off:expr, $val:expr) => { 47 | $raw[$off + 0] = ($val & 0x000000ff) as u8; 48 | $raw[$off + 1] = (($val & 0x0000ff00) >> 8) as u8; 49 | $raw[$off + 2] = (($val & 0x00ff0000) >> 16) as u8; 50 | $raw[$off + 3] = (($val & 0xff000000) >> 24) as u8; 51 | }; 52 | } 53 | 54 | macro_rules! read_u64_le { 55 | ($raw:expr, $off:expr) => { 56 | (($raw[$off + 7] as u64) << 56) 57 | | (($raw[$off + 6] as u64) << 48) 58 | | (($raw[$off + 5] as u64) << 40) 59 | | (($raw[$off + 4] as u64) << 32) 60 | | (($raw[$off + 3] as u64) << 24) 61 | | (($raw[$off + 2] as u64) << 16) 62 | | (($raw[$off + 1] as u64) << 8) 63 | | ($raw[$off] as u64) 64 | }; 65 | } 66 | 67 | macro_rules! write_u64_le { 68 | ($raw:expr, $off:expr, $val:expr) => { 69 | $raw[$off+0] = ($val & 0x00000000_000000ff) as u8; 70 | $raw[$off+1] = (($val & 0x00000000_0000ff00) >> 8) as u8; 71 | $raw[$off+2] = (($val & 0x00000000_00ff0000) >> 16) as u8; 72 | $raw[$off+3] = (($val & 0x00000000_ff000000) >> 24) as u8; 73 | $raw[$off+4] = (($val & 0x000000ff_00000000) >> 32) as u8; 74 | $raw[$off+5] = (($val & 0x0000ff00_00000000) >> 40) as u8; 75 | $raw[$off+6] = (($val & 0x00ff0000_00000000) >> 48) as u8; 76 | $raw[$off+7] = (($val & 0xff000000_00000000) >> 56) as u8; 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/emu/maps/mem64.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Little endian 64 bits and inferior bits memory. 3 | */ 4 | 5 | use md5; 6 | use std::fs::File; 7 | use std::io::prelude::*; 8 | use std::io::BufReader; 9 | use std::io::Read; 10 | use std::io::SeekFrom; 11 | use std::io::Write; 12 | 13 | #[derive(Clone)] 14 | pub struct Mem64 { 15 | mem_name: String, 16 | base_addr: u64, 17 | bottom_addr: u64, 18 | pub mem: Vec, 19 | } 20 | 21 | impl Mem64 { 22 | pub fn new() -> Mem64 { 23 | Mem64 { 24 | mem_name: "".to_string(), 25 | base_addr: 0, 26 | bottom_addr: 0, 27 | mem: Vec::new(), 28 | } 29 | } 30 | 31 | pub fn get_name(&self) -> String { 32 | return self.mem_name.clone(); 33 | } 34 | 35 | pub fn set_name(&mut self, name: &str) { 36 | self.mem_name = name.to_string(); 37 | } 38 | 39 | pub fn get_mem(&self) -> Vec { 40 | return self.mem.clone(); 41 | } 42 | 43 | pub fn alloc(&mut self, amount: usize) { 44 | self.mem = vec![0; amount]; 45 | } 46 | 47 | pub fn extend(&mut self, amount: usize) { 48 | for i in 0..amount { 49 | self.mem.push(0); 50 | } 51 | self.bottom_addr += amount as u64; 52 | } 53 | 54 | pub fn size(&self) -> usize { 55 | self.mem.len() 56 | } 57 | 58 | pub fn get_base(&self) -> u64 { 59 | self.base_addr 60 | } 61 | 62 | pub fn get_bottom(&self) -> u64 { 63 | self.bottom_addr 64 | } 65 | 66 | pub fn memcpy(&mut self, ptr: &[u8], sz: usize) { 67 | if self.mem.len() < sz { 68 | panic!("memcpy: {} < {}", self.mem.len(), sz); 69 | } 70 | for i in 0..sz { 71 | self.mem[i] = ptr[i]; 72 | } 73 | } 74 | 75 | pub fn inside(&self, addr: u64) -> bool { 76 | if addr >= self.base_addr && addr < self.bottom_addr { 77 | return true; 78 | } 79 | false 80 | } 81 | 82 | pub fn set_base(&mut self, base_addr: u64) { 83 | self.base_addr = base_addr; 84 | self.bottom_addr = base_addr; 85 | } 86 | 87 | pub fn update_base(&mut self, base_addr: u64) { 88 | self.base_addr = base_addr; 89 | } 90 | 91 | pub fn set_bottom(&mut self, bottom_addr: u64) { 92 | self.bottom_addr = bottom_addr; 93 | let size = self.bottom_addr - self.base_addr; 94 | self.alloc(size as usize); 95 | } 96 | 97 | pub fn update_bottom(&mut self, bottom_addr: u64) { 98 | self.bottom_addr = bottom_addr; 99 | } 100 | 101 | pub fn set_size(&mut self, size: u64) { 102 | self.bottom_addr = self.base_addr + size; 103 | self.alloc(size as usize); 104 | } 105 | 106 | pub fn read_from(&self, addr: u64) -> &[u8] { 107 | let idx = (addr - self.base_addr) as usize; 108 | let max_sz = (self.bottom_addr - self.base_addr) as usize; 109 | /* 110 | let mut sz = idx + 5; 111 | if sz > max_sz { 112 | sz = max_sz; 113 | }*/ 114 | return self.mem.get(idx..max_sz).unwrap(); 115 | } 116 | 117 | pub fn read_bytes(&self, addr: u64, sz: usize) -> &[u8] { 118 | let idx = (addr - self.base_addr) as usize; 119 | let sz2 = idx as usize + sz; 120 | if sz2 > self.mem.len() { 121 | return &[0; 0]; 122 | } 123 | return self.mem.get(idx..sz2).unwrap(); 124 | } 125 | 126 | pub fn read_byte(&self, addr: u64) -> u8 { 127 | assert!(self.inside(addr)); 128 | 129 | let idx = (addr - self.base_addr) as usize; 130 | if idx < self.mem.len() { 131 | self.mem[idx] 132 | } else { 133 | panic!("reading at 0x{:x}", addr); 134 | } 135 | } 136 | 137 | pub fn read_word(&self, addr: u64) -> u16 { 138 | let idx = (addr - self.base_addr) as usize; 139 | (self.mem[idx] as u16) + ((self.mem[idx + 1] as u16) << 8) 140 | } 141 | 142 | pub fn read_dword(&self, addr: u64) -> u32 { 143 | let idx = (addr - self.base_addr) as usize; 144 | (self.mem[idx] as u32) 145 | + ((self.mem[idx + 1] as u32) << 8) 146 | + ((self.mem[idx + 2] as u32) << 16) 147 | + ((self.mem[idx + 3] as u32) << 24) 148 | } 149 | 150 | pub fn read_qword(&self, addr: u64) -> u64 { 151 | let idx = (addr - self.base_addr) as usize; 152 | let mut r: u64 = 0; 153 | 154 | for i in 0..8 { 155 | r |= (self.mem[idx + i] as u64) << (8 * i); 156 | } 157 | 158 | r 159 | } 160 | 161 | pub fn write_byte(&mut self, addr: u64, value: u8) { 162 | let idx = (addr - self.base_addr) as usize; 163 | self.mem[idx] = value; 164 | } 165 | 166 | pub fn write_bytes(&mut self, addr: u64, bs: &[u8]) { 167 | let idx = (addr - self.base_addr) as usize; 168 | for i in 0..bs.len() { 169 | self.mem[idx + i] = bs[i]; 170 | } 171 | } 172 | 173 | pub fn write_word(&mut self, addr: u64, value: u16) { 174 | let idx = (addr - self.base_addr) as usize; 175 | self.mem[idx] = (value & 0x00ff) as u8; 176 | self.mem[idx + 1] = ((value & 0xff00) >> 8) as u8; 177 | } 178 | 179 | pub fn write_dword(&mut self, addr: u64, value: u32) { 180 | let idx = (addr - self.base_addr) as usize; 181 | assert!(idx < self.mem.len()); 182 | self.mem[idx] = (value & 0x000000ff) as u8; 183 | self.mem[idx + 1] = ((value & 0x0000ff00) >> 8) as u8; 184 | self.mem[idx + 2] = ((value & 0x00ff0000) >> 16) as u8; 185 | self.mem[idx + 3] = ((value & 0xff000000) >> 24) as u8; 186 | } 187 | 188 | pub fn write_qword(&mut self, addr: u64, value: u64) { 189 | let idx = (addr - self.base_addr) as usize; 190 | for i in 0..8 { 191 | self.mem[idx + i] = ((value >> (i * 8)) & 0xff) as u8; 192 | } 193 | } 194 | 195 | pub fn write_string(&mut self, addr: u64, s: &str) { 196 | let mut v = s.as_bytes().to_vec(); 197 | v.push(0); 198 | self.write_bytes(addr, &v); 199 | } 200 | 201 | pub fn write_wide_string(&mut self, addr: u64, s: &str) { 202 | let mut wv: Vec = Vec::new(); 203 | let v = s.as_bytes().to_vec(); 204 | for b in v { 205 | wv.push(b); 206 | wv.push(0); 207 | } 208 | wv.push(0); 209 | wv.push(0); 210 | self.write_bytes(addr, &wv); 211 | } 212 | 213 | pub fn print_bytes(&self) { 214 | log::info!("---mem---"); 215 | for b in self.mem.iter() { 216 | print!("{}", b); 217 | } 218 | log::info!("---"); 219 | } 220 | 221 | pub fn print_dwords(&self) { 222 | self.print_dwords_from_to(self.get_base(), self.get_bottom()); 223 | } 224 | 225 | pub fn print_dwords_from_to(&self, from: u64, to: u64) { 226 | log::info!("---mem---"); 227 | for addr in (from..to).step_by(4) { 228 | log::info!("0x{:x}", self.read_dword(addr)) 229 | } 230 | 231 | log::info!("---"); 232 | } 233 | 234 | pub fn md5(&self) -> md5::Digest { 235 | md5::compute(&self.mem) 236 | } 237 | 238 | pub fn load_at(&mut self, base_addr: u64) { 239 | self.set_base(base_addr); 240 | let mut name: String = String::from(&self.mem_name); 241 | name.push_str(".bin"); 242 | self.load(name.as_str()); 243 | } 244 | 245 | pub fn load_chunk(&mut self, filename: &str, off: u64, sz: usize) -> bool { 246 | // log::info!("loading chunk: {} {} {}", filename, off, sz); 247 | let mut f = match File::open(&filename) { 248 | Ok(f) => f, 249 | Err(_) => { 250 | return false; 251 | } 252 | }; 253 | f.seek(SeekFrom::Start(off)); 254 | let mut reader = BufReader::new(&f); 255 | self.mem.clear(); 256 | for i in 0..sz { 257 | self.mem.push(0); 258 | } 259 | reader 260 | .read_exact(&mut self.mem) 261 | .expect("cannot load chunk of file"); 262 | f.sync_all(); // thanks Alberto Segura 263 | true 264 | } 265 | 266 | pub fn load(&mut self, filename: &str) -> bool { 267 | // log::info!("loading map: {}", filename); 268 | let f = match File::open(&filename) { 269 | Ok(f) => f, 270 | Err(_) => { 271 | return false; 272 | } 273 | }; 274 | let len = f.metadata().unwrap().len(); 275 | self.bottom_addr = self.base_addr + len; 276 | let mut reader = BufReader::new(&f); 277 | reader 278 | .read_to_end(&mut self.mem) 279 | .expect("cannot load map file"); 280 | f.sync_all(); // thanks Alberto Segura 281 | true 282 | } 283 | 284 | pub fn save(&self, addr: u64, size: usize, filename: String) { 285 | let idx = (addr - self.base_addr) as usize; 286 | let sz2 = idx as usize + size; 287 | if sz2 > self.mem.len() { 288 | log::info!("size too big, map size is {} sz2:{}", self.mem.len(), sz2); 289 | return; 290 | } 291 | 292 | let mut f = match File::create(filename) { 293 | Ok(f) => f, 294 | Err(e) => { 295 | log::info!("cannot create the file {}", e); 296 | return; 297 | } 298 | }; 299 | 300 | let blob = self.mem.get(idx..sz2).unwrap(); 301 | 302 | match f.write_all(blob) { 303 | Ok(_) => log::info!("saved."), 304 | Err(_) => log::info!("couldn't save the file"), 305 | } 306 | 307 | f.sync_all().unwrap(); 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /src/emu/ntapi32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | /* 3 | use crate::emu::console; 4 | use crate::emu::constants; 5 | use crate::emu::context32; 6 | use crate::emu::peb32; 7 | use crate::emu::structures; 8 | use lazy_static::lazy_static; 9 | use std::sync::Mutex; 10 | */ 11 | 12 | pub fn gateway(syscall: u64, argv: u64, emu: &mut emu::Emu) { 13 | match syscall { 14 | 0xdc => { 15 | log::info!("/!\\ direct syscall: NtAlpcSendWaitReceivePort"); 16 | emu.regs.rax = 0; 17 | } 18 | 19 | 0x10f => { 20 | log::info!("/!\\ direct syscall: NtOpenFile {:x}", argv); 21 | emu.regs.rax = 0; 22 | } 23 | 24 | _ => { 25 | log::info!( 26 | "{}{} 0x{:x}: {}{}", 27 | emu.colors.red, 28 | emu.pos, 29 | emu.regs.rip, 30 | emu.out, 31 | emu.colors.nc 32 | ); 33 | unimplemented!(); 34 | } 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/emu/peb32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::structures::LdrDataTableEntry; 3 | use crate::emu::structures::OrdinalTable; 4 | use crate::emu::structures::PEB; 5 | use crate::emu::structures::TEB; 6 | use crate::emu::structures::PebLdrData; 7 | 8 | pub fn init_ldr(emu: &mut emu::Emu) -> u64 { 9 | let ldr_sz = PebLdrData::size(); 10 | let ldr_addr = emu.maps.lib32_alloc(ldr_sz as u64).expect("cannot alloc the LDR"); 11 | emu.maps.create_map("ldr", ldr_addr, ldr_sz as u64).expect("cannot create ldr map"); 12 | let module_entry = create_ldr_entry(emu, 0, 0, "loader.exe", 0, 0) as u32; 13 | let mut ldr = PebLdrData::new(); 14 | ldr.initializated = 1; 15 | ldr.in_load_order_module_list.flink = module_entry; 16 | ldr.in_load_order_module_list.blink = module_entry; 17 | ldr.in_memory_order_module_list.flink = module_entry+0x8; 18 | ldr.in_memory_order_module_list.blink = module_entry+0x8; 19 | ldr.in_initialization_order_module_list.flink = module_entry+0x10; 20 | ldr.in_initialization_order_module_list.blink = module_entry+0x10; 21 | ldr.entry_in_progress = module_entry; 22 | ldr.save(ldr_addr, &mut emu.maps); 23 | 24 | return ldr_addr; 25 | } 26 | 27 | 28 | 29 | pub fn init_peb(emu: &mut emu::Emu) { 30 | let ldr = init_ldr(emu); 31 | 32 | let peb_addr = emu.maps.lib32_alloc(PEB::size() as u64).expect("cannot alloc the PEB32"); 33 | let mut peb_map = emu.maps.create_map("peb", peb_addr, PEB::size() as u64).expect("cannot create peb map"); 34 | let process_parameters = 0x521e20; 35 | let peb = PEB::new(0, ldr as u32, process_parameters); 36 | peb.save(&mut peb_map); 37 | 38 | let teb_addr = emu.maps.lib32_alloc(TEB::size() as u64).expect("cannot alloc the TEB32"); 39 | let mut teb_map = emu.maps.create_map("teb", teb_addr, TEB::size() as u64).expect("cannot create teb map"); 40 | let teb = TEB::new(peb_addr as u32); 41 | teb.save(&mut teb_map); 42 | } 43 | 44 | pub fn update_peb_image_base(emu: &mut emu::Emu, base: u32) { 45 | let peb = emu.maps.get_mem("peb"); 46 | let peb_base = peb.get_base(); 47 | emu.maps.write_dword(peb_base + 0x10, base); 48 | } 49 | 50 | #[derive(Debug)] 51 | pub struct Flink { 52 | flink_addr: u64, 53 | pub mod_base: u64, 54 | pub mod_name: String, 55 | pub pe_hdr: u64, 56 | 57 | pub export_table_rva: u64, 58 | pub export_table: u64, 59 | pub num_of_funcs: u64, 60 | pub func_name_tbl_rva: u64, 61 | pub func_name_tbl: u64, 62 | } 63 | 64 | impl Flink { 65 | pub fn save(&mut self, emu: &mut emu::Emu) {} 66 | 67 | pub fn new(emu: &mut emu::Emu) -> Flink { 68 | let peb = emu.maps.get_mem("peb"); 69 | let peb_base = peb.get_base(); 70 | let ldr = peb.read_dword(peb_base + 0x0c) as u64; // peb->ldr 71 | let flink = emu 72 | .maps 73 | .read_dword(ldr + 0x0c) 74 | .expect("peb32::new() error reading flink") as u64; 75 | 76 | Flink { 77 | flink_addr: flink, 78 | mod_base: 0, 79 | mod_name: String::new(), 80 | pe_hdr: 0, 81 | export_table_rva: 0, 82 | export_table: 0, 83 | num_of_funcs: 0, 84 | func_name_tbl_rva: 0, 85 | func_name_tbl: 0, 86 | } 87 | } 88 | 89 | pub fn print(&self) { 90 | log::info!("{:#x?}", self); 91 | } 92 | 93 | pub fn get_ptr(&self) -> u64 { 94 | return self.flink_addr; 95 | } 96 | 97 | pub fn set_ptr(&mut self, addr: u64) { 98 | self.flink_addr = addr; 99 | } 100 | 101 | pub fn load(&mut self, emu: &mut emu::Emu) { 102 | self.get_mod_base(emu); 103 | self.get_mod_name(emu); 104 | self.get_pe_hdr(emu); 105 | self.get_export_table(emu); 106 | } 107 | 108 | pub fn get_mod_base(&mut self, emu: &mut emu::Emu) { 109 | self.mod_base = emu 110 | .maps 111 | .read_dword(self.flink_addr + 0x18) 112 | .expect("error reading mod_addr") as u64; 113 | } 114 | 115 | pub fn set_mod_base(&mut self, base: u64, emu: &mut emu::Emu) { 116 | emu.maps.write_dword(self.flink_addr + 0x18, base as u32); 117 | } 118 | 119 | pub fn get_mod_name(&mut self, emu: &mut emu::Emu) { 120 | let mod_name_ptr = emu 121 | .maps 122 | .read_dword(self.flink_addr + 0x38) //0x28 123 | .expect("error reading mod_name_ptr") as u64; 124 | self.mod_name = emu.maps.read_wide_string(mod_name_ptr); 125 | } 126 | 127 | pub fn has_module(&self) -> bool { 128 | if self.mod_base == 0 || self.flink_addr == 0 { 129 | return false; 130 | } 131 | return true; 132 | } 133 | 134 | pub fn get_pe_hdr(&mut self, emu: &mut emu::Emu) { 135 | self.pe_hdr = match emu.maps.read_dword(self.mod_base + 0x3c) { 136 | Some(hdr) => hdr as u64, 137 | None => 0, 138 | }; 139 | } 140 | 141 | pub fn get_export_table(&mut self, emu: &mut emu::Emu) { 142 | if self.pe_hdr == 0 { 143 | return; 144 | } 145 | 146 | 147 | //log::info!("base: 0x{:x} + pe_hdr {} + 0x78 = {}", self.mod_base, self.pe_hdr, self.mod_base + self.pe_hdr + 0x78); 148 | self.export_table_rva = match emu.maps 149 | .read_dword(self.mod_base + self.pe_hdr + 0x78) { 150 | Some(v) => v as u64, 151 | None => { 152 | // .expect("error reading export_table_rva") as u64; 153 | return; 154 | } 155 | }; 156 | 157 | if self.export_table_rva == 0 { 158 | return; 159 | } 160 | 161 | self.export_table = self.export_table_rva + self.mod_base; 162 | self.num_of_funcs = match emu.maps.read_dword(self.export_table + 0x18) { 163 | Some(num_of_funcs) => num_of_funcs as u64, 164 | None => { 165 | log::info!( 166 | "error reading export_table 0x{:x} = 0x{:x} + 0x{:x}", 167 | self.export_table, self.export_table_rva, self.mod_base 168 | ); 169 | 0 170 | } 171 | }; 172 | 173 | if self.num_of_funcs > 0 { 174 | self.func_name_tbl_rva = 175 | emu.maps 176 | .read_dword(self.export_table + 0x20) 177 | .expect(" error reading func_name_tbl_rva") as u64; 178 | self.func_name_tbl = self.func_name_tbl_rva + self.mod_base; 179 | } 180 | } 181 | 182 | pub fn get_function_ordinal(&self, emu: &mut emu::Emu, function_id: u64) -> OrdinalTable { 183 | let mut ordinal = OrdinalTable::new(); 184 | 185 | let func_name_rva = match emu.maps.read_dword(self.func_name_tbl + function_id * 4) { 186 | Some(addr) => addr as u64, 187 | None => return ordinal, 188 | }; 189 | 190 | if func_name_rva == 0 { 191 | ordinal.func_name = "-".to_string(); 192 | } else { 193 | ordinal.func_name = emu.maps.read_string(func_name_rva + self.mod_base); 194 | } 195 | 196 | if ordinal.func_name == "VCOMPort" { 197 | emu.spawn_console(); 198 | } 199 | 200 | 201 | ordinal.ordinal_tbl_rva = emu 202 | .maps 203 | .read_dword(self.export_table + 0x24) 204 | .expect("error reading ordinal_tbl_rva") as u64; 205 | ordinal.ordinal_tbl = ordinal.ordinal_tbl_rva + self.mod_base; 206 | ordinal.ordinal = emu 207 | .maps 208 | .read_word(ordinal.ordinal_tbl + 2 * function_id) 209 | .expect("error reading ordinal") as u64; 210 | ordinal.func_addr_tbl_rva = emu 211 | .maps 212 | .read_dword(self.export_table + 0x1c) 213 | .expect("error reading func_addr_tbl_rva") as u64; 214 | ordinal.func_addr_tbl = ordinal.func_addr_tbl_rva + self.mod_base; 215 | ordinal.func_rva = emu 216 | .maps 217 | .read_dword(ordinal.func_addr_tbl + 4 * ordinal.ordinal) 218 | .expect("error reading func_rva") as u64; 219 | ordinal.func_va = ordinal.func_rva + self.mod_base; 220 | 221 | ordinal 222 | } 223 | 224 | pub fn get_next_flink(&self, emu: &mut emu::Emu) -> u64 { 225 | return emu 226 | .maps 227 | .read_dword(self.flink_addr) 228 | .expect("error reading next flink") as u64; 229 | } 230 | 231 | pub fn get_prev_flink(&self, emu: &mut emu::Emu) -> u64 { 232 | return emu 233 | .maps 234 | .read_dword(self.flink_addr + 4) 235 | .expect("error reading prev flink") as u64; 236 | } 237 | 238 | pub fn next(&mut self, emu: &mut emu::Emu) { 239 | self.flink_addr = self.get_next_flink(emu); 240 | self.load(emu); 241 | } 242 | } 243 | 244 | pub fn get_module_base(libname: &str, emu: &mut emu::Emu) -> Option { 245 | let mut libname2: String = libname.to_string().to_lowercase(); 246 | if !libname2.ends_with(".dll") { 247 | libname2.push_str(".dll"); 248 | } 249 | 250 | let mut flink = Flink::new(emu); 251 | flink.load(emu); 252 | let first_flink = flink.get_ptr(); 253 | loop { 254 | //log::info!("{} == {}", libname2, flink.mod_name); 255 | 256 | if libname.to_string().to_lowercase() == flink.mod_name.to_string().to_lowercase() 257 | || libname2 == flink.mod_name.to_string().to_lowercase() 258 | { 259 | return Some(flink.mod_base); 260 | } 261 | flink.next(emu); 262 | 263 | if flink.get_ptr() == first_flink { 264 | break; 265 | } 266 | } 267 | return None; 268 | } 269 | 270 | pub fn show_linked_modules(emu: &mut emu::Emu) { 271 | let mut flink = Flink::new(emu); 272 | flink.load(emu); 273 | let first_flink = flink.get_ptr(); 274 | 275 | // get last element 276 | loop { 277 | let pe1 = match emu.maps.read_byte(flink.mod_base + flink.pe_hdr) { 278 | Some(b) => b, 279 | None => 0, 280 | }; 281 | let pe2 = match emu.maps.read_byte(flink.mod_base + flink.pe_hdr + 1) { 282 | Some(b) => b, 283 | None => 0, 284 | }; 285 | log::info!( 286 | "0x{:x} {} flink:{:x} blink:{:x} base:{:x} pe_hdr:{:x} {:x}{:x}", 287 | flink.get_ptr(), 288 | flink.mod_name, 289 | flink.get_next_flink(emu), 290 | flink.get_prev_flink(emu), 291 | flink.mod_base, 292 | flink.pe_hdr, 293 | pe1, 294 | pe2 295 | ); 296 | flink.next(emu); 297 | if flink.get_ptr() == first_flink { 298 | return; 299 | } 300 | } 301 | } 302 | 303 | pub fn update_ldr_entry_base(libname: &str, base: u64, emu: &mut emu::Emu) { 304 | let mut flink = Flink::new(emu); 305 | flink.load(emu); 306 | while flink.mod_name.to_lowercase() != libname.to_lowercase() { 307 | flink.next(emu); 308 | } 309 | flink.set_mod_base(base, emu); 310 | } 311 | 312 | pub fn dynamic_unlink_module(libname: &str, emu: &mut emu::Emu) { 313 | let mut prev_flink: u64 = 0; 314 | let next_flink: u64; 315 | 316 | let mut flink = Flink::new(emu); 317 | flink.load(emu); 318 | while flink.mod_name != libname { 319 | log::info!("{}", flink.mod_name); 320 | prev_flink = flink.get_ptr(); 321 | flink.next(emu); 322 | } 323 | 324 | flink.next(emu); 325 | next_flink = flink.get_ptr(); 326 | 327 | // previous flink 328 | log::info!("prev_flink: 0x{:x}", prev_flink); 329 | //emu.maps.write_dword(prev_flink, next_flink as u32); 330 | emu.maps.write_dword(prev_flink, 0); 331 | 332 | // next blink 333 | log::info!("next_flink: 0x{:x}", next_flink); 334 | emu.maps.write_dword(next_flink + 4, prev_flink as u32); 335 | 336 | show_linked_modules(emu); 337 | } 338 | 339 | pub fn dynamic_link_module(base: u64, pe_off: u32, libname: &str, emu: &mut emu::Emu) { 340 | /* 341 | * LoadLibary* family triggers this. 342 | */ 343 | 344 | let mut last_flink: u64; 345 | let mut flink = Flink::new(emu); 346 | flink.load(emu); 347 | let first_flink = flink.get_ptr(); 348 | 349 | // get last element 350 | loop { 351 | //last_flink = flink.get_ptr(); commented on 64bits 352 | flink.next(emu); 353 | if flink.get_next_flink(emu) == first_flink { 354 | break; 355 | } 356 | } 357 | let next_flink: u64 = flink.get_ptr(); 358 | 359 | //first_flink = 0x2c18c0; 360 | //let space_addr = create_ldr_entry(emu, base, pe_off, libname, last_flink, first_flink); 361 | let space_addr = create_ldr_entry(emu, base as u32, pe_off, libname, first_flink as u32, next_flink as u32); 362 | 363 | 364 | // point previous flink to this ldr 365 | emu.maps.write_dword(next_flink, space_addr as u32); // in_load_order_links.flink 366 | emu.maps.write_dword(next_flink + 0x08, (space_addr + 0x08) as u32); // in_memory_order_links.flink 367 | emu.maps.write_dword(next_flink + 0x10, (space_addr + 0x10) as u32); // in_initialization_order_links.flink 368 | 369 | // blink of first flink will point to last created 370 | emu.maps.write_dword(first_flink + 4, space_addr as u32); // in_load_order_links.blink 371 | emu.maps.write_dword(first_flink + 0x08 + 4, (space_addr + 0x08) as u32); // in_memory_order_links.blink 372 | emu.maps.write_dword(first_flink + 0x10 + 4, (space_addr + 0x10) as u32); // in_initialization_order_links.blink 373 | 374 | //show_linked_modules(emu); 375 | } 376 | 377 | 378 | pub fn create_ldr_entry_prev( 379 | emu: &mut emu::Emu, 380 | base: u64, 381 | pe_off: u32, 382 | libname: &str, 383 | next_flink: u64, 384 | prev_flink: u64, 385 | ) -> u64 { 386 | // make space for ldr 387 | let sz = LdrDataTableEntry::size() as u64 + 0x40 + 1024; 388 | let space_addr = emu 389 | .maps 390 | .alloc(sz) 391 | .expect("cannot alloc few bytes to put the LDR for LoadLibraryA"); 392 | let mut lib = libname.to_string(); 393 | lib.push_str(".ldr"); 394 | let mem = emu.maps.create_map(lib.as_str(), space_addr, sz).expect("cannot create ldr entry map"); 395 | mem.write_byte(space_addr + sz - 1, 0x61); 396 | 397 | 398 | //mem.write_dword(space_addr, next_flink as u32); 399 | mem.write_dword(space_addr, prev_flink as u32); //0x2c18c0); 400 | mem.write_dword(space_addr + 4, next_flink as u32); 401 | //mem.write_dword(space_addr+0x10, next_flink as u32); // in_memory_order_linked_list 402 | mem.write_dword(space_addr + 0x10, base as u32); // in_memory_order_linked_list 403 | // 404 | mem.write_dword(space_addr + 0x1c, base as u32); // entry_point? 405 | mem.write_dword(space_addr + 0x3c, pe_off); 406 | mem.write_dword(space_addr + 0x28, space_addr as u32 + 0x40); // libname ptr 407 | mem.write_dword(space_addr + 0x30, space_addr as u32 + 0x40); // libname ptr 408 | mem.write_wide_string(space_addr + 0x40, &(libname.to_string() + "\x00")); 409 | mem.write_word(space_addr + 0x26, libname.len() as u16 * 2 + 2); // undocumented field used on a cobalt strike sample. 410 | 411 | space_addr 412 | } 413 | 414 | pub fn create_ldr_entry( 415 | emu: &mut emu::Emu, 416 | base: u32, 417 | entry_point: u32, 418 | libname: &str, 419 | next_flink: u32, 420 | prev_flink: u32, 421 | ) -> u64 { 422 | // make space for ldr 423 | let sz = (LdrDataTableEntry::size() + 0x40 + (1024*2)) as u64; 424 | let space_addr = emu 425 | .maps 426 | .alloc(sz) 427 | .expect("cannot alloc few bytes to put the LDR for LoadLibraryA"); 428 | let mut lib = libname.to_string(); 429 | lib.push_str(".ldr"); 430 | let mut image_sz = 0; 431 | if base > 0 { 432 | let pe_hdr = emu.maps.read_dword(base as u64 + 0x3c).unwrap() as u64; 433 | image_sz = emu.maps.read_dword(base as u64 + pe_hdr + 0x50).unwrap() as u64; 434 | } 435 | let mem = emu.maps.create_map(lib.as_str(), space_addr, sz).expect("create_ldr_entry cannot create map"); 436 | mem.write_byte(space_addr + sz - 1, 0x61); 437 | 438 | let full_libname = "C:\\Windows\\System32\\".to_string() + &libname.to_string(); 439 | let mut ldr = LdrDataTableEntry::new(); 440 | if next_flink != 0 { 441 | ldr.in_load_order_links.flink = next_flink; 442 | ldr.in_load_order_links.blink = prev_flink; 443 | ldr.in_memory_order_links.flink = next_flink+0x8; 444 | ldr.in_memory_order_links.blink = prev_flink+0x8; 445 | ldr.in_initialization_order_links.flink = next_flink+0x10; 446 | ldr.in_initialization_order_links.blink = prev_flink+0x10; 447 | ldr.hash_links.flink = next_flink+0x44; 448 | ldr.hash_links.blink = prev_flink+0x44; 449 | } else { 450 | ldr.in_load_order_links.flink = space_addr as u32; 451 | ldr.in_load_order_links.blink = space_addr as u32; 452 | ldr.in_memory_order_links.flink = space_addr as u32+0x8; 453 | ldr.in_memory_order_links.blink = space_addr as u32+0x8; 454 | ldr.in_initialization_order_links.flink = space_addr as u32+0x10; 455 | ldr.in_initialization_order_links.blink = space_addr as u32+0x10; 456 | ldr.hash_links.flink = space_addr as u32+0x44; 457 | ldr.hash_links.blink = space_addr as u32+0x44; 458 | } 459 | ldr.dll_base = base; 460 | ldr.entry_point = entry_point; 461 | ldr.size_of_image = image_sz as u32; 462 | ldr.full_dll_name.length = full_libname.len() as u16 * 2; 463 | ldr.full_dll_name.maximum_length = full_libname.len() as u16 * 2 + 4; 464 | ldr.full_dll_name.buffer = space_addr as u32 + LdrDataTableEntry::size() as u32; 465 | ldr.base_dll_name.length = libname.len() as u16 * 2; 466 | ldr.base_dll_name.maximum_length = libname.len() as u16 * 2 + 2; 467 | ldr.base_dll_name.buffer = space_addr as u32 + LdrDataTableEntry::size() as u32 + full_libname.len() as u32 * 2 + 10; 468 | ldr.flags = 0; 469 | ldr.load_count = 0; 470 | ldr.tls_index = 0; 471 | ldr.hash_links.flink = next_flink; 472 | ldr.hash_links.blink = prev_flink; 473 | mem.write_wide_string(space_addr as u64 + LdrDataTableEntry::size() as u64, &(full_libname.clone() + "\x00\x00")); 474 | mem.write_wide_string(space_addr as u64 + LdrDataTableEntry::size() as u64 + full_libname.len() as u64 * 2 +10, &(libname.to_string() + "\x00")); 475 | ldr.save(space_addr, &mut emu.maps); 476 | 477 | // http://terminus.rewolf.pl/terminus/structures/ntdll/_LDR_DATA_TABLE_ENTRY_x64.html 478 | 479 | space_addr 480 | } 481 | 482 | -------------------------------------------------------------------------------- /src/emu/peb64.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::structures::LdrDataTableEntry64; 3 | use crate::emu::structures::OrdinalTable; 4 | use crate::emu::structures::PEB64; 5 | use crate::emu::structures::TEB64; 6 | use crate::emu::structures::PebLdrData64; 7 | 8 | pub fn init_ldr(emu: &mut emu::Emu) -> u64 { 9 | let ldr_sz = PebLdrData64::size(); 10 | let ldr_addr = emu.maps.lib64_alloc(ldr_sz as u64).expect("cannot alloc the LDR"); 11 | emu.maps.create_map("ldr", ldr_addr, ldr_sz as u64).expect("cannot create ldr map"); 12 | let module_entry = create_ldr_entry(emu, 0, 0, "loader.exe", 0, 0); 13 | let mut ldr = PebLdrData64::new(); 14 | ldr.initializated = 1; 15 | ldr.in_load_order_module_list.flink = module_entry; 16 | ldr.in_load_order_module_list.blink = module_entry; 17 | ldr.in_memory_order_module_list.flink = module_entry+0x10; 18 | ldr.in_memory_order_module_list.blink = module_entry+0x10; 19 | ldr.in_initialization_order_module_list.flink = module_entry+0x20; 20 | ldr.in_initialization_order_module_list.blink = module_entry+0x20; 21 | ldr.entry_in_progress.flink = module_entry; 22 | ldr.entry_in_progress.blink = module_entry; 23 | ldr.save(ldr_addr, &mut emu.maps); 24 | 25 | return ldr_addr; 26 | } 27 | 28 | pub fn init_peb(emu: &mut emu::Emu) { 29 | let ldr = init_ldr(emu); 30 | 31 | let peb_addr = emu.maps.lib64_alloc(PEB64::size() as u64).expect("cannot alloc the PEB64"); 32 | let mut peb_map = emu.maps.create_map("peb", peb_addr, PEB64::size() as u64).expect("cannot create peb map"); 33 | let process_parameters = 0x521e20; 34 | let peb = PEB64::new(0, ldr, process_parameters); 35 | peb.save(&mut peb_map); 36 | emu.maps.write_byte(peb_addr + 2, 0); // not being_debugged 37 | 38 | let teb_addr = emu.maps.lib64_alloc(TEB64::size() as u64).expect("cannot alloc the TEB64"); 39 | let mut teb_map = emu.maps.create_map("teb", teb_addr, TEB64::size() as u64).expect("cannot create teb map"); 40 | let teb = TEB64::new(peb_addr); 41 | teb.save(&mut teb_map); 42 | 43 | } 44 | 45 | pub fn update_peb_image_base(emu: &mut emu::Emu, base: u64) { 46 | let peb = emu.maps.get_mem("peb"); 47 | let peb_base = peb.get_base(); 48 | emu.maps.write_qword(peb_base + 0x10, base); 49 | } 50 | 51 | 52 | #[derive(Debug)] 53 | pub struct Flink { 54 | flink_addr: u64, 55 | pub mod_base: u64, 56 | pub mod_name: String, 57 | pub pe_hdr: u64, 58 | 59 | pub export_table_rva: u64, 60 | pub export_table: u64, 61 | pub num_of_funcs: u64, 62 | pub func_name_tbl_rva: u64, 63 | pub func_name_tbl: u64, 64 | } 65 | 66 | impl Flink { 67 | pub fn new(emu: &mut emu::Emu) -> Flink { 68 | let peb = emu.maps.get_mem("peb"); 69 | let peb_base = peb.get_base(); 70 | let ldr = peb.read_qword(peb_base + 0x18); // peb->ldr 71 | let flink = emu 72 | .maps 73 | .read_qword(ldr + 0x10) 74 | .expect("peb64::new() error reading flink"); 75 | 76 | Flink { 77 | flink_addr: flink, 78 | mod_base: 0, 79 | mod_name: String::new(), 80 | pe_hdr: 0, 81 | export_table_rva: 0, 82 | export_table: 0, 83 | num_of_funcs: 0, 84 | func_name_tbl_rva: 0, 85 | func_name_tbl: 0, 86 | } 87 | } 88 | 89 | pub fn print(&self) { 90 | log::info!("{:#x?}", self); 91 | } 92 | 93 | pub fn get_ptr(&self) -> u64 { 94 | return self.flink_addr; 95 | } 96 | 97 | pub fn set_ptr(&mut self, addr: u64) { 98 | self.flink_addr = addr; 99 | } 100 | 101 | pub fn load(&mut self, emu: &mut emu::Emu) { 102 | self.get_mod_base(emu); 103 | self.get_mod_name(emu); 104 | self.get_pe_hdr(emu); 105 | self.get_export_table(emu); 106 | } 107 | 108 | pub fn get_mod_base(&mut self, emu: &mut emu::Emu) { 109 | self.mod_base = emu 110 | .maps 111 | .read_qword(self.flink_addr + 0x30) 112 | .expect("error reading mod_addr"); 113 | } 114 | 115 | pub fn set_mod_base(&mut self, base: u64, emu: &mut emu::Emu) { 116 | self.mod_base = base; 117 | emu.maps.write_qword(self.flink_addr + 0x30, base); 118 | } 119 | 120 | pub fn get_mod_name(&mut self, emu: &mut emu::Emu) { 121 | let mod_name_ptr = emu 122 | .maps 123 | .read_qword(self.flink_addr + 0x60) 124 | .expect("error reading mod_name_ptr"); 125 | self.mod_name = emu.maps.read_wide_string(mod_name_ptr); 126 | } 127 | 128 | pub fn has_module(&self) -> bool { 129 | if self.mod_base == 0 || self.flink_addr == 0 { 130 | return false; 131 | } 132 | return true; 133 | } 134 | 135 | pub fn get_pe_hdr(&mut self, emu: &mut emu::Emu) { 136 | self.pe_hdr = match emu.maps.read_dword(self.mod_base + 0x3c) { 137 | Some(hdr) => hdr as u64, 138 | None => 0, 139 | }; 140 | } 141 | 142 | pub fn get_export_table(&mut self, emu: &mut emu::Emu) { 143 | if self.pe_hdr == 0 { 144 | return; 145 | } 146 | 147 | //log::info!("mod_base 0x{:x} pe_hdr 0x{:x}", self.mod_base, self.pe_hdr); 148 | 149 | self.export_table_rva = match emu 150 | .maps 151 | .read_dword(self.mod_base + self.pe_hdr + 0x88) { 152 | Some(rva) => rva as u64, 153 | None => 0, 154 | }; 155 | 156 | if self.export_table_rva == 0 { 157 | return; 158 | } 159 | 160 | self.export_table = self.export_table_rva + self.mod_base; 161 | 162 | //////// 163 | /* 164 | emu.maps.print_maps(); 165 | log::info!("rva: 0x{:x} = 0x{:x} + 0x{:x} + 0x88 -> 0x{:x}", 166 | self.mod_base+self.pe_hdr+0x88, 167 | self.mod_base, 168 | self.pe_hdr, 169 | self.export_table_rva); 170 | log::info!("export_table: 0x{:x} = 0x{:x} + 0x{:x}", 171 | self.export_table, 172 | self.mod_base, 173 | self.export_table_rva); 174 | log::info!("num_of_funcs [0x{:x} + 0x18] = [0x{:x}]", 175 | self.export_table, 176 | self.export_table+0x18); 177 | */ 178 | 179 | 180 | self.num_of_funcs = emu 181 | .maps 182 | .read_dword(self.export_table + 0x18) 183 | .expect("error reading the num_of_funcs") as u64; 184 | self.func_name_tbl_rva = emu 185 | .maps 186 | .read_dword(self.export_table + 0x20) 187 | .expect(" error reading func_name_tbl_rva") as u64; 188 | self.func_name_tbl = self.func_name_tbl_rva + self.mod_base; 189 | } 190 | 191 | pub fn get_function_ordinal(&self, emu: &mut emu::Emu, function_id: u64) -> OrdinalTable { 192 | let mut ordinal = OrdinalTable::new(); 193 | let func_name_rva = emu 194 | .maps 195 | .read_dword(self.func_name_tbl + function_id * 4) 196 | .expect("error reading func_rva") as u64; 197 | ordinal.func_name = emu.maps.read_string(func_name_rva + self.mod_base); 198 | ordinal.ordinal_tbl_rva = emu 199 | .maps 200 | .read_dword(self.export_table + 0x24) 201 | .expect("error reading ordinal_tbl_rva") as u64; 202 | ordinal.ordinal_tbl = ordinal.ordinal_tbl_rva + self.mod_base; 203 | ordinal.ordinal = emu 204 | .maps 205 | .read_word(ordinal.ordinal_tbl + 2 * function_id) 206 | .expect("error reading ordinal") as u64; 207 | ordinal.func_addr_tbl_rva = emu 208 | .maps 209 | .read_dword(self.export_table + 0x1c) 210 | .expect("error reading func_addr_tbl_rva") as u64; 211 | ordinal.func_addr_tbl = ordinal.func_addr_tbl_rva + self.mod_base; 212 | ordinal.func_rva = emu 213 | .maps 214 | .read_dword(ordinal.func_addr_tbl + 4 * ordinal.ordinal) 215 | .expect("error reading func_rva") as u64; 216 | ordinal.func_va = ordinal.func_rva + self.mod_base; 217 | 218 | ordinal 219 | } 220 | 221 | pub fn get_next_flink(&self, emu: &mut emu::Emu) -> u64 { 222 | return emu 223 | .maps 224 | .read_qword(self.flink_addr) 225 | .expect("error reading next flink") as u64; 226 | } 227 | 228 | pub fn get_prev_flink(&self, emu: &mut emu::Emu) -> u64 { 229 | return emu 230 | .maps 231 | .read_qword(self.flink_addr + 8) 232 | .expect("error reading prev flink") as u64; 233 | } 234 | 235 | pub fn next(&mut self, emu: &mut emu::Emu) { 236 | self.flink_addr = self.get_next_flink(emu); 237 | self.load(emu); 238 | } 239 | } 240 | 241 | pub fn get_module_base(libname: &str, emu: &mut emu::Emu) -> Option { 242 | let mut libname2: String = libname.to_string().to_lowercase(); 243 | if !libname2.ends_with(".dll") { 244 | libname2.push_str(".dll"); 245 | } 246 | 247 | let mut flink = Flink::new(emu); 248 | flink.load(emu); 249 | 250 | let first_flink = flink.get_ptr(); 251 | loop { 252 | //log::info!("{} == {}", libname2, flink.mod_name); 253 | 254 | if libname.to_string().to_lowercase() == flink.mod_name.to_string().to_lowercase() 255 | || libname2 == flink.mod_name.to_string().to_lowercase() 256 | { 257 | return Some(flink.mod_base); 258 | } 259 | flink.next(emu); 260 | 261 | if flink.get_ptr() == first_flink { 262 | break; 263 | } 264 | } 265 | return None; 266 | } 267 | 268 | pub fn show_linked_modules(emu: &mut emu::Emu) { 269 | let mut flink = Flink::new(emu); 270 | flink.load(emu); 271 | let first_flink = flink.get_ptr(); 272 | 273 | // get last element 274 | loop { 275 | let pe1 = match emu.maps.read_byte(flink.mod_base + flink.pe_hdr) { 276 | Some(b) => b, 277 | None => 0, 278 | }; 279 | let pe2 = match emu.maps.read_byte(flink.mod_base + flink.pe_hdr + 1) { 280 | Some(b) => b, 281 | None => 0, 282 | }; 283 | log::info!( 284 | "0x{:x} {} flink:{:x} blink:{:x} base:{:x} pe_hdr:{:x} {:x}{:x}", 285 | flink.get_ptr(), 286 | flink.mod_name, 287 | flink.get_next_flink(emu), 288 | flink.get_prev_flink(emu), 289 | flink.mod_base, 290 | flink.pe_hdr, 291 | pe1, 292 | pe2 293 | ); 294 | flink.next(emu); 295 | if flink.get_ptr() == first_flink { 296 | return; 297 | } 298 | } 299 | } 300 | 301 | pub fn update_ldr_entry_base(libname: &str, base: u64, emu: &mut emu::Emu) { 302 | let mut flink = Flink::new(emu); 303 | flink.load(emu); 304 | while flink.mod_name.to_lowercase() != libname.to_lowercase() { 305 | flink.next(emu); 306 | } 307 | flink.set_mod_base(base, emu); 308 | } 309 | 310 | pub fn dynamic_unlink_module(libname: &str, emu: &mut emu::Emu) { 311 | let mut prev_flink: u64 = 0; 312 | let next_flink: u64; 313 | 314 | let mut flink = Flink::new(emu); 315 | flink.load(emu); 316 | while flink.mod_name != libname { 317 | log::info!("{}", flink.mod_name); 318 | prev_flink = flink.get_ptr(); 319 | flink.next(emu); 320 | } 321 | 322 | flink.next(emu); 323 | next_flink = flink.get_ptr(); 324 | 325 | // previous flink 326 | log::info!("prev_flink: 0x{:x}", prev_flink); 327 | //emu.maps.write_qword(prev_flink, next_flink); 328 | emu.maps.write_qword(prev_flink, 0); 329 | 330 | // next blink 331 | log::info!("next_flink: 0x{:x}", next_flink); 332 | emu.maps.write_qword(next_flink + 4, prev_flink); 333 | 334 | show_linked_modules(emu); 335 | } 336 | 337 | pub fn dynamic_link_module(base: u64, pe_off: u32, libname: &str, emu: &mut emu::Emu) { 338 | /* 339 | * LoadLibary* family triggers this. 340 | */ 341 | //log::info!("************ dynamic_link_module {}", libname); 342 | let mut last_flink: u64; 343 | let mut flink = Flink::new(emu); 344 | flink.load(emu); 345 | let first_flink = flink.get_ptr(); 346 | 347 | // get last element 348 | loop { 349 | //last_flink = flink.get_ptr(); 350 | flink.next(emu); 351 | if flink.get_next_flink(emu) == first_flink { 352 | break; 353 | } 354 | } 355 | let next_flink: u64 = flink.get_ptr(); 356 | 357 | //log::info!("last: {} {:x}", flink.mod_name, next_flink); 358 | 359 | //let space_addr = create_ldr_entry(emu, base, pe_off, libname, last_flink, first_flink); 360 | let space_addr = create_ldr_entry(emu, base, pe_off.into(), libname, first_flink, next_flink /*first_flink*/); 361 | //TODO: pe_off is entry point 362 | 363 | // point previous flink to this ldr 364 | //let repl1 = emu.maps.read_qword(next_flink).unwrap(); 365 | emu.maps.write_qword(next_flink, space_addr); // in_load_order_links.flink 366 | emu.maps.write_qword(next_flink+0x10, space_addr+0x10); // in_memory_order_links.flink 367 | emu.maps.write_qword(next_flink+0x20, space_addr+0x20); // in_initialization_order_links.flink 368 | 369 | // blink of first flink will point to last created 370 | emu.maps.write_qword(first_flink + 8, space_addr); // in_load_order_links.blink 371 | emu.maps.write_qword(first_flink+0x10+8, space_addr+0x10); // in_memory_order_links.blink 372 | emu.maps.write_qword(first_flink+0x20+8, space_addr+0x20); // in_initialization_order_links.blink 373 | 374 | 375 | //show_linked_modules(emu); 376 | } 377 | 378 | pub fn create_ldr_entry( 379 | emu: &mut emu::Emu, 380 | base: u64, 381 | entry_point: u64, 382 | libname: &str, 383 | next_flink: u64, 384 | prev_flink: u64, 385 | ) -> u64 { 386 | // make space for ldr 387 | let sz = LdrDataTableEntry64::size() + 0x40 + (1024*2); 388 | let space_addr = emu 389 | .maps 390 | .alloc(sz) 391 | .expect("cannot alloc few bytes to put the LDR for LoadLibraryA"); 392 | let mut lib = libname.to_string(); 393 | lib.push_str(".ldr"); 394 | let mut image_sz = 0; 395 | if base > 0 { 396 | let pe_hdr = emu.maps.read_dword(base as u64 + 0x3c).unwrap() as u64; 397 | image_sz = emu.maps.read_qword(base as u64 + pe_hdr + 0x50).unwrap() as u64; 398 | } 399 | let mem = emu.maps.create_map(lib.as_str(), space_addr, sz).expect("cannot create ldr entry map"); 400 | mem.write_byte(space_addr + sz - 1, 0x61); 401 | 402 | //let full_libname = "\"C:\\Windows\\System32\\".to_string() + &libname.to_string() + "\"\x00"; 403 | let full_libname = "C:\\Windows\\System32\\".to_string() + &libname.to_string(); 404 | 405 | let mut ldr = LdrDataTableEntry64::new(); 406 | if next_flink != 0 { 407 | ldr.in_load_order_links.flink = next_flink; 408 | ldr.in_load_order_links.blink = prev_flink; 409 | ldr.in_memory_order_links.flink = next_flink+0x10; 410 | ldr.in_memory_order_links.blink = prev_flink+0x10; 411 | ldr.in_initialization_order_links.flink = next_flink+0x20; 412 | ldr.in_initialization_order_links.blink = prev_flink+0x20; 413 | ldr.hash_links.flink = next_flink+0x7f; 414 | ldr.hash_links.blink = prev_flink+0x7f; 415 | } else { 416 | ldr.in_load_order_links.flink = space_addr; 417 | ldr.in_load_order_links.blink = space_addr; 418 | ldr.in_memory_order_links.flink = space_addr+0x10; 419 | ldr.in_memory_order_links.blink = space_addr+0x10; 420 | ldr.in_initialization_order_links.flink = space_addr+0x20; 421 | ldr.in_initialization_order_links.blink = space_addr+0x20; 422 | ldr.hash_links.flink = space_addr+0x7f; 423 | ldr.hash_links.blink = space_addr+0x7f; 424 | } 425 | ldr.dll_base = base; 426 | ldr.entry_point = entry_point; 427 | ldr.size_of_image = image_sz; 428 | ldr.full_dll_name.length = full_libname.len() as u16 * 2; 429 | ldr.full_dll_name.maximum_length = full_libname.len() as u16 * 2 + 4; 430 | ldr.full_dll_name.buffer = space_addr + LdrDataTableEntry64::size(); 431 | ldr.base_dll_name.length = libname.len() as u16 * 2; 432 | ldr.base_dll_name.maximum_length = libname.len() as u16 * 2 + 2; 433 | ldr.base_dll_name.buffer = space_addr + LdrDataTableEntry64::size() + full_libname.len() as u64 * 2 + 10; 434 | ldr.flags = 0; 435 | ldr.load_count = 0; 436 | ldr.tls_index = 0; 437 | ldr.hash_links.flink = next_flink; 438 | ldr.hash_links.blink = prev_flink; 439 | mem.write_wide_string(space_addr + LdrDataTableEntry64::size(), &(full_libname.clone() + "\x00\x00")); 440 | mem.write_wide_string(space_addr + LdrDataTableEntry64::size() + full_libname.len() as u64 * 2 +10, &(libname.to_string() + "\x00")); 441 | ldr.save(space_addr, &mut emu.maps); 442 | 443 | // http://terminus.rewolf.pl/terminus/structures/ntdll/_LDR_DATA_TABLE_ENTRY_x64.html 444 | 445 | space_addr 446 | } 447 | -------------------------------------------------------------------------------- /src/emu/winapi32.rs: -------------------------------------------------------------------------------- 1 | mod advapi32; 2 | mod crypt32; 3 | mod dnsapi; 4 | pub mod helper; 5 | pub mod kernel32; 6 | mod kernelbase; 7 | mod mscoree; 8 | mod msvcrt; 9 | mod ntdll; 10 | mod oleaut32; 11 | mod shlwapi; 12 | mod user32; 13 | mod wininet; 14 | mod ws2_32; 15 | mod libgcc; 16 | mod iphlpapi; 17 | mod wincrt; 18 | 19 | use crate::emu; 20 | 21 | pub fn gateway(addr: u32, name: String, emu: &mut emu::Emu) { 22 | log::info!("winapi32::gateway called with addr: 0x{:x}, name: {}", addr, name); 23 | 24 | emu.regs.sanitize32(); 25 | let unimplemented_api = match name.as_str() { 26 | "kernel32.text" => kernel32::gateway(addr, emu), 27 | "kernel32.rdata" => kernel32::gateway(addr, emu), 28 | "ntdll.text" => ntdll::gateway(addr, emu), 29 | "user32.text" => user32::gateway(addr, emu), 30 | "ws2_32.text" => ws2_32::gateway(addr, emu), 31 | "wininet.text" => wininet::gateway(addr, emu), 32 | "advapi32.text" => advapi32::gateway(addr, emu), 33 | "crypt32.text" => crypt32::gateway(addr, emu), 34 | "dnsapi.text" => dnsapi::gateway(addr, emu), 35 | "mscoree.text" => mscoree::gateway(addr, emu), 36 | "msvcrt.text" => msvcrt::gateway(addr, emu), 37 | "shlwapi.text" => shlwapi::gateway(addr, emu), 38 | "oleaut32.text" => oleaut32::gateway(addr, emu), 39 | "kernelbase.text" => kernelbase::gateway(addr, emu), 40 | "iphlpapi.text" => iphlpapi::gateway(addr, emu), 41 | "libgcc_s_dw2-1.text" => libgcc::gateway(addr, emu), 42 | "api-ms-win-crt-runtime-l1-1-0.text" => wincrt::gateway(addr, emu), 43 | "not_loaded" => { 44 | emu.pe32.as_ref().unwrap().import_addr_to_name(addr as u32) 45 | } 46 | _ => { 47 | log::info!("/!\\ trying to execute on {} at 0x{:x}", name, addr); 48 | name.clone() 49 | } 50 | }; 51 | 52 | if unimplemented_api.len() > 0 { 53 | let params = emu.banzai.get_params(&unimplemented_api); 54 | log::info!("{} {} parameters", unimplemented_api, params); 55 | 56 | if name != "msvcrt.text" { 57 | for _ in 0..params { 58 | emu.stack_pop32(false); 59 | } 60 | } 61 | 62 | emu.regs.rax = 1; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/emu/winapi32/crypt32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::winapi32::kernel32; 3 | /* 4 | use crate::emu::winapi32::helper; 5 | use crate::emu::context32; 6 | use crate::emu::constants; 7 | use crate::emu::console; 8 | */ 9 | 10 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 11 | let api = kernel32::guess_api_name(emu, addr); 12 | match api.as_str() { 13 | "PkiInitializeCriticalSection" => PkiInitializeCriticalSection(emu), 14 | "CryptStringToBinaryA" => CryptStringToBinaryA(emu), 15 | 16 | _ => { 17 | log::info!( 18 | "calling unimplemented crypt32 API 0x{:x} {}", 19 | addr, api 20 | ); 21 | return api; 22 | } 23 | } 24 | 25 | return String::new(); 26 | } 27 | 28 | fn PkiInitializeCriticalSection(emu: &mut emu::Emu) { 29 | let addr = emu 30 | .maps 31 | .read_dword(emu.regs.get_esp()) 32 | .expect("crypt32!PkiInitializeCriticalSection error getting flags param"); 33 | let flags = emu 34 | .maps 35 | .read_dword(emu.regs.get_esp() + 4) 36 | .expect("crypt32!PkiInitializeCriticalSection error getting addr param"); 37 | 38 | log::info!( 39 | "{}** {} crypt32!Pki_InitializeCriticalSection flags: {:x} addr: 0x{:x} {}", 40 | emu.colors.light_red, emu.pos, flags, addr, emu.colors.nc 41 | ); 42 | 43 | for _ in 0..2 { 44 | emu.stack_pop32(false); 45 | } 46 | emu.regs.rax = 1; 47 | } 48 | 49 | fn CryptStringToBinaryA(emu: &mut emu::Emu) { 50 | let string = emu 51 | .maps 52 | .read_dword(emu.regs.get_esp()) 53 | .expect("crypt32!CryptStringToBinaryA error getting flags param"); 54 | let num_chars = emu 55 | .maps 56 | .read_dword(emu.regs.get_esp() + 4) 57 | .expect("crypt32!PCryptStringToBinaryA error getting addr param"); 58 | let flags = emu 59 | .maps 60 | .read_dword(emu.regs.get_esp() + 8) 61 | .expect("crypt32!CryptStringToBinaryA error getting flags param"); 62 | let ptr = emu 63 | .maps 64 | .read_dword(emu.regs.get_esp() + 12) 65 | .expect("crypt32!PCryptStringToBinaryA error getting addr param"); 66 | let inout_sz = emu 67 | .maps 68 | .read_dword(emu.regs.get_esp() + 16) 69 | .expect("crypt32!CryptStringToBinaryA error getting flags param"); 70 | let skip = emu 71 | .maps 72 | .read_dword(emu.regs.get_esp() + 20) 73 | .expect("crypt32!PCryptStringToBinaryA error getting addr param"); 74 | let out_flags = emu 75 | .maps 76 | .read_dword(emu.regs.get_esp() + 24) 77 | .expect("crypt32!CryptStringToBinaryA error getting flags param"); 78 | 79 | let dflags = match flags { 80 | 0x00000000 => "CRYPT_STRING_BASE64HEADER", 81 | 0x00000001 => "CRYPT_STRING_BASE64", 82 | 0x00000002 => "CRYPT_STRING_BINARY", 83 | 0x00000003 => "CRYPT_STRING_BASE64REQUESTHEADER", 84 | 0x00000004 => "CRYPT_STRING_HEX", 85 | 0x00000005 => "CRYPT_STRING_HEXASCII", 86 | 0x00000006 => "CRYPT_STRING_BASE64_ANY", 87 | 0x00000007 => "CRYPT_STRING_ANY", 88 | 0x00000008 => "CRYPT_STRING_HEX_ANY", 89 | 0x00000009 => "CRYPT_STRING_BASE64X509CRLHEADER", 90 | 0x0000000a => "CRYPT_STRING_HEXADDR", 91 | 0x0000000b => "CRYPT_STRING_HEXASCIIADDR", 92 | 0x0000000c => "CRYPT_STRING_HEXRAW", 93 | 0x20000000 => "CRYPT_STRING_STRICT", 94 | _ => "incorrect flag", 95 | }; 96 | 97 | log::info!( 98 | "{}** {} crypt32!CryptStringToBinaryA str: 0x{:x} len: {} ptr: {} len: {} {}{}", 99 | emu.colors.light_red, emu.pos, string, num_chars, ptr, inout_sz, dflags, emu.colors.nc 100 | ); 101 | 102 | for _ in 0..7 { 103 | emu.stack_pop32(false); 104 | } 105 | emu.regs.rax = 1; 106 | } 107 | -------------------------------------------------------------------------------- /src/emu/winapi32/dnsapi.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::winapi32::kernel32; 3 | //use crate::emu::winapi32::helper; 4 | //use crate::emu::endpoint; 5 | 6 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 7 | let api = kernel32::guess_api_name(emu, addr); 8 | match api.as_str() { 9 | "DnsQuery_A" => DnsQuery_A(emu), 10 | "DnsQueryA" => DnsQuery_A(emu), 11 | "DnsQuery_W" => DnsQuery_W(emu), 12 | "DnsQueryW" => DnsQuery_W(emu), 13 | 14 | _ => { 15 | log::info!("calling unimplemented dnsapi API 0x{:x} {}", addr, api); 16 | return api; 17 | } 18 | } 19 | 20 | return String::new(); 21 | } 22 | 23 | fn DnsQuery_A(emu: &mut emu::Emu) { 24 | let name_ptr = emu 25 | .maps 26 | .read_dword(emu.regs.get_esp()) 27 | .expect("dnsapi!DnsQuery_A cant read name ptr param") as u64; 28 | let wtype = emu 29 | .maps 30 | .read_dword(emu.regs.get_esp() + 4) 31 | .expect("dnsapi!DnsQuery_A cant read wtype pram"); 32 | let opt = emu 33 | .maps 34 | .read_dword(emu.regs.get_esp() + 8) 35 | .expect("dnsapi!DnsQuery_A cant read options param"); 36 | let extra = emu 37 | .maps 38 | .read_dword(emu.regs.get_esp() + 12) 39 | .expect("dnsapi!DnsQuery_A cant read extra param"); 40 | let out_results = emu 41 | .maps 42 | .read_dword(emu.regs.get_esp() + 16) 43 | .expect("dnsapi!DnsQuery_A cant read out results param"); 44 | let out_reserved = emu 45 | .maps 46 | .read_dword(emu.regs.get_esp() + 20) 47 | .expect("dnsapi!DnsQuery_A cant read out reserved param"); 48 | 49 | let name = emu.maps.read_string(name_ptr); 50 | 51 | log::info!( 52 | "{}** {} dnsapi!DnsQuery_A '{}' {}", 53 | emu.colors.light_red, emu.pos, name, emu.colors.nc 54 | ); 55 | 56 | emu.regs.rax = 1; 57 | } 58 | 59 | fn DnsQuery_W(emu: &mut emu::Emu) { 60 | let name_ptr = emu 61 | .maps 62 | .read_dword(emu.regs.get_esp()) 63 | .expect("dnsapi!DnsQuery_W cant read name ptr param") as u64; 64 | let wtype = emu 65 | .maps 66 | .read_dword(emu.regs.get_esp() + 4) 67 | .expect("dnsapi!DnsQuery_W cant read wtype pram"); 68 | let opt = emu 69 | .maps 70 | .read_dword(emu.regs.get_esp() + 8) 71 | .expect("dnsapi!DnsQuery_W cant read options param"); 72 | let extra = emu 73 | .maps 74 | .read_dword(emu.regs.get_esp() + 12) 75 | .expect("dnsapi!DnsQuery_W cant read extra param"); 76 | let out_results = emu 77 | .maps 78 | .read_dword(emu.regs.get_esp() + 16) 79 | .expect("dnsapi!DnsQuery_W cant read out results param"); 80 | let out_reserved = emu 81 | .maps 82 | .read_dword(emu.regs.get_esp() + 20) 83 | .expect("dnsapi!DnsQuery_W cant read out reserved param"); 84 | 85 | let name = emu.maps.read_wide_string(name_ptr); 86 | 87 | log::info!( 88 | "{}** {} dnsapi!DnsQuery_W '{}' {}", 89 | emu.colors.light_red, emu.pos, name, emu.colors.nc 90 | ); 91 | 92 | emu.regs.rax = 1; 93 | } 94 | -------------------------------------------------------------------------------- /src/emu/winapi32/helper.rs: -------------------------------------------------------------------------------- 1 | use lazy_static::lazy_static; 2 | use std::sync::Mutex; 3 | 4 | pub struct Handler { 5 | id: u64, 6 | uri: String, 7 | data: Vec, 8 | } 9 | 10 | impl Handler { 11 | fn new(id: u64, uri: &str) -> Handler { 12 | Handler { 13 | id: id, 14 | uri: uri.to_string(), 15 | data: vec![], 16 | } 17 | } 18 | } 19 | 20 | lazy_static! { 21 | static ref HANDLERS: Mutex> = Mutex::new(Vec::new()); 22 | static ref SOCKETS: Mutex> = Mutex::new(vec![0; 0]); 23 | } 24 | 25 | pub fn handler_create(uri: &str) -> u64 { 26 | let new_id: u64; 27 | let mut handles = HANDLERS.lock().unwrap(); 28 | 29 | if handles.len() == 0 { 30 | new_id = 1; 31 | } else { 32 | let last_id = handles[handles.len() - 1].id; 33 | new_id = last_id + 1; 34 | } 35 | 36 | let new_handler = Handler::new(new_id, uri); 37 | 38 | handles.push(new_handler); 39 | return new_id; 40 | } 41 | 42 | pub fn handler_close(hndl: u64) -> bool { 43 | let mut handles = HANDLERS.lock().unwrap(); 44 | let idx = match handles.iter().position(|h| (*h).id == hndl) { 45 | Some(i) => i, 46 | None => return false, 47 | }; 48 | handles.remove(idx); 49 | return true; 50 | } 51 | 52 | pub fn handler_print() { 53 | let hndls = HANDLERS.lock().unwrap(); 54 | for h in hndls.iter() { 55 | log::info!("{:x} {}", h.id, h.uri); 56 | } 57 | } 58 | 59 | pub fn handler_exist(hndl: u64) -> bool { 60 | let handles = HANDLERS.lock().unwrap(); 61 | match handles.iter().position(|h| (*h).id == hndl) { 62 | Some(_) => return true, 63 | None => return false, 64 | } 65 | } 66 | 67 | pub fn handler_put_bytes(hndl: u64, data: &[u8]) { 68 | let mut handles = HANDLERS.lock().unwrap(); 69 | match handles.iter().position(|h| (*h).id == hndl) { 70 | Some(idx) => handles[idx].data = data.to_vec(), 71 | None => (), 72 | } 73 | } 74 | 75 | pub fn handler_get_uri(hndl: u64) -> String { 76 | let handles = HANDLERS.lock().unwrap(); 77 | match handles.iter().position(|h| (*h).id == hndl) { 78 | Some(idx) => return handles[idx].uri.clone(), 79 | None => return String::new(), 80 | } 81 | } 82 | 83 | pub fn socket_create() -> u64 { 84 | let new_socket: u64; 85 | let mut sockets = SOCKETS.lock().unwrap(); 86 | 87 | if sockets.len() == 0 { 88 | sockets.push(0); // stdin 89 | sockets.push(1); // stdout 90 | sockets.push(2); // stderr 91 | new_socket = 3; // first available socket 92 | } else { 93 | let last_socket = sockets[sockets.len() - 1]; 94 | new_socket = last_socket + 1; 95 | } 96 | 97 | sockets.push(new_socket); 98 | return new_socket; 99 | } 100 | 101 | pub fn socket_close(sock: u64) -> bool { 102 | let mut sockets = SOCKETS.lock().unwrap(); 103 | let idx = match sockets.iter().position(|s| *s == sock) { 104 | Some(i) => i, 105 | None => return false, 106 | }; 107 | sockets.remove(idx); 108 | return true; 109 | } 110 | 111 | pub fn socket_exist(sock: u64) -> bool { 112 | let sockets = SOCKETS.lock().unwrap(); 113 | match sockets.iter().position(|s| *s == sock) { 114 | Some(_) => return true, 115 | None => return false, 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/emu/winapi32/iphlpapi.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::winapi32::kernel32; 3 | 4 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 5 | let api = kernel32::guess_api_name(emu, addr); 6 | match api.as_str() { 7 | //"LoadLibraryA" => LoadLibraryA(emu), 8 | _ => { 9 | log::info!( 10 | "calling unimplemented iphlpapi API 0x{:x} {}", 11 | addr, api 12 | ); 13 | return api; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/emu/winapi32/kernelbase.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | //use crate::emu::console; 3 | //use crate::emu::constants; 4 | //use crate::emu::context32; 5 | //use crate::emu::peb32; 6 | //use crate::emu::structures; 7 | //use crate::emu::winapi32::helper; 8 | use crate::emu::winapi32::kernel32; 9 | 10 | use lazy_static::lazy_static; 11 | use std::sync::Mutex; 12 | 13 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 14 | let api = kernel32::guess_api_name(emu, addr); 15 | match api.as_str() { 16 | "LoadStringW" => LoadStringW(emu), 17 | "_initterm" => _initterm(emu), 18 | "_initterm_e" => _initterm_e(emu), 19 | 20 | _ => { 21 | log::info!("calling unimplemented kernelbase API 0x{:x} {}", addr, api); 22 | return api; 23 | } 24 | } 25 | 26 | return String::new(); 27 | } 28 | 29 | lazy_static! { 30 | static ref COUNT_READ: Mutex = Mutex::new(0); 31 | static ref COUNT_WRITE: Mutex = Mutex::new(0); 32 | pub static ref TICK: Mutex = Mutex::new(0); 33 | static ref LAST_ERROR: Mutex = Mutex::new(0); 34 | } 35 | 36 | //// kernelbase API //// 37 | 38 | fn LoadStringW(emu: &mut emu::Emu) { 39 | let hndl = emu.maps.read_dword(emu.regs.rsp) 40 | .expect("kernelbase!LoadStringW error reading param"); 41 | let id = emu.maps.read_dword(emu.regs.rsp+4) 42 | .expect("kernelbase!LoadStringW error reading param"); 43 | let buff = emu.maps.read_dword(emu.regs.rsp+8) 44 | .expect("kernelbase!LoadStringW error reading param"); 45 | let len = emu.maps.read_dword(emu.regs.rsp+12) 46 | .expect("kernelbase!LoadStringW error reading param"); 47 | 48 | log::info!( 49 | "{}** {} kernelbase!LoadStringW {} 0x{} {}", 50 | emu.colors.light_red, emu.pos, id, buff, emu.colors.nc, 51 | ); 52 | 53 | emu.stack_pop32(false); 54 | emu.stack_pop32(false); 55 | emu.stack_pop32(false); 56 | emu.stack_pop32(false); 57 | emu.regs.rax = 1; 58 | } 59 | 60 | fn _initterm(emu: &mut emu::Emu) { 61 | let ptr1 = emu.maps.read_dword(emu.regs.rsp) 62 | .expect("kernelbase!_initterm error reading param"); 63 | let ptr2 = emu.maps.read_dword(emu.regs.rsp+4) 64 | .expect("kernelbase!_initterm error reading param"); 65 | log::info!("{}** {} kernelbase!_initterm 0x{:x} 0x{:x} {}", emu.colors.light_red, emu.pos, ptr1, ptr2, emu.colors.nc); 66 | emu.stack_pop32(false); 67 | emu.stack_pop32(false); 68 | emu.regs.rax = 0; 69 | } 70 | 71 | fn _initterm_e(emu: &mut emu::Emu) { 72 | let ptr1 = emu.maps.read_dword(emu.regs.rsp) 73 | .expect("kernelbase!_initterm_e error reading param"); 74 | let ptr2 = emu.maps.read_dword(emu.regs.rsp+4) 75 | .expect("kernelbase!_initterm_e error reading param"); 76 | log::info!("{}** {} kernelbase!_initterm_e 0x{:x} 0x{:x} {}", emu.colors.light_red, emu.pos, ptr1, ptr2, emu.colors.nc); 77 | emu.stack_pop32(false); 78 | emu.stack_pop32(false); 79 | emu.regs.rax = 0; 80 | } 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/emu/winapi32/libgcc.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | //use crate::emu::constants::*; 3 | //use crate::emu::winapi32::helper; 4 | use crate::emu::winapi32::kernel32; 5 | 6 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 7 | let api = kernel32::guess_api_name(emu, addr); 8 | match api.as_str() { 9 | "__register_frame_info" => __register_frame_info(emu), 10 | "__deregister_frame_info" => __deregister_frame_info(emu), 11 | 12 | 13 | _ => { 14 | log::info!("calling unimplemented libgcc API 0x{:x} {}", addr, api); 15 | return api; 16 | } 17 | } 18 | 19 | return String::new(); 20 | } 21 | 22 | 23 | fn __register_frame_info(emu: &mut emu::Emu) { 24 | let p1 = 25 | emu.maps 26 | .read_dword(emu.regs.get_esp()) 27 | .expect("advapi32!__register_frame_info error reading param"); 28 | let p2 = 29 | emu.maps 30 | .read_dword(emu.regs.get_esp()+4) 31 | .expect("advapi32!__register_frame_info error reading param"); 32 | 33 | log::info!( 34 | "{}** {} libgcc!__register_frame_info {:x} {:x} {}", 35 | emu.colors.light_red, emu.pos, p1, p2, emu.colors.nc 36 | ); 37 | 38 | let mem = match emu.maps.get_mem_by_addr(0x40E198) { 39 | Some(m) => m, 40 | None => { 41 | emu.maps.create_map("glob1", 0x40E198, 100).expect("cannot create glob1 map") 42 | } 43 | }; 44 | 45 | mem.write_dword(0x40E198, 0x6e940000); 46 | 47 | 48 | for _ in 0..2 { 49 | emu.stack_pop32(false); 50 | } 51 | emu.regs.rax = 1; 52 | } 53 | 54 | 55 | fn __deregister_frame_info(emu: &mut emu::Emu) { 56 | let p1 = 57 | emu.maps 58 | .read_dword(emu.regs.get_esp()) 59 | .expect("advapi32!__deregister_frame_info error reading param"); 60 | 61 | log::info!( 62 | "{}** {} libgcc!__deregister_frame_info {:x} {}", 63 | emu.colors.light_red, emu.pos, p1, emu.colors.nc 64 | ); 65 | 66 | emu.stack_pop32(false); 67 | emu.regs.rax = 1; 68 | } 69 | -------------------------------------------------------------------------------- /src/emu/winapi32/mscoree.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::winapi32::kernel32; 3 | 4 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 5 | let api = kernel32::guess_api_name(emu, addr); 6 | match api.as_str() { 7 | "_CorExeMain" => _CorExeMain(emu), 8 | 9 | _ => { 10 | log::info!("calling unimplemented mscoree API 0x{:x} {}", addr, api); 11 | return api; 12 | } 13 | } 14 | 15 | return String::new(); 16 | } 17 | 18 | pub fn _CorExeMain(emu: &mut emu::Emu) { 19 | log::info!( 20 | "{}** {} mscoree!_CorExeMain {}", 21 | emu.colors.light_red, emu.pos, emu.colors.nc 22 | ); 23 | emu.regs.rax = 1; 24 | unimplemented!(); 25 | } 26 | -------------------------------------------------------------------------------- /src/emu/winapi32/msvcrt.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::winapi32::helper; 3 | use crate::emu::winapi32::kernel32; 4 | //use crate::emu::endpoint; 5 | 6 | // msvcrt is an exception and these functions dont have to compensate the stack. 7 | 8 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 9 | let api = kernel32::guess_api_name(emu, addr); 10 | match api.as_str() { 11 | "_initterm_e" => _initterm_e(emu), 12 | "_initterm" => _initterm(emu), 13 | "StrCmpCA" => StrCmpCA(emu), 14 | "fopen" => fopen(emu), 15 | "fwrite" => fwrite(emu), 16 | "fflush" => fflush(emu), 17 | "fclose" => fclose(emu), 18 | "__p___argv" => __p___argv(emu), 19 | "__p___argc" => __p___argc(emu), 20 | "malloc" => malloc(emu), 21 | "_onexit" => _onexit(emu), 22 | "_lock" => _lock(emu), 23 | "free" => free(emu), 24 | "realloc" => realloc(emu), 25 | "strtok" => strtok(emu), 26 | 27 | _ => { 28 | log::info!("calling unimplemented msvcrt API 0x{:x} {}", addr, api); 29 | return api; 30 | } 31 | } 32 | 33 | return String::new(); 34 | } 35 | 36 | fn _initterm_e(emu: &mut emu::Emu) { 37 | let start_ptr = emu 38 | .maps 39 | .read_dword(emu.regs.get_esp()) 40 | .expect("msvcrt!_initterm_e: error reading start pointer") as u64; 41 | let end_ptr = emu 42 | .maps 43 | .read_dword(emu.regs.get_esp() + 4) 44 | .expect("msvcrt!_initterm_e: error reading en pointer") as u64; 45 | 46 | log::info!( 47 | "{}** {} msvcrt!_initterm_e 0x{:x} - 0x{:x} {}", 48 | emu.colors.light_red, emu.pos, start_ptr, end_ptr, emu.colors.nc 49 | ); 50 | 51 | //emu.stack_pop32(false); 52 | //emu.stack_pop32(false); 53 | emu.regs.rax = 0; 54 | } 55 | 56 | fn _initterm(emu: &mut emu::Emu) { 57 | let start_ptr = emu 58 | .maps 59 | .read_dword(emu.regs.get_esp()) 60 | .expect("msvcrt!_initterm_e: error reading start pointer") as u64; 61 | let end_ptr = emu 62 | .maps 63 | .read_dword(emu.regs.get_esp() + 4) 64 | .expect("msvcrt!_initterm_e: error reading end pointer") as u64; 65 | 66 | log::info!( 67 | "{}** {} msvcrt!_initterm 0x{:x} - 0x{:x} {}", 68 | emu.colors.light_red, emu.pos, start_ptr, end_ptr, emu.colors.nc 69 | ); 70 | 71 | //emu.stack_pop32(false); 72 | //emu.stack_pop32(false); 73 | emu.regs.rax = 0; 74 | } 75 | 76 | fn StrCmpCA(emu: &mut emu::Emu) { 77 | let str1_ptr = emu 78 | .maps 79 | .read_dword(emu.regs.get_esp()) 80 | .expect("msvcrt!StrCmpA: error reading str1 pointer") as u64; 81 | let str2_ptr = emu 82 | .maps 83 | .read_dword(emu.regs.get_esp() + 4) 84 | .expect("msvcrt!StrCmpA: error reading str2 pointer") as u64; 85 | 86 | let str1 = emu.maps.read_string(str1_ptr); 87 | let str2 = emu.maps.read_string(str2_ptr); 88 | 89 | log::info!( 90 | "{}** {} msvcrt!StrCmpA {} == {} {}", 91 | emu.colors.light_red, emu.pos, str1, str2, emu.colors.nc 92 | ); 93 | 94 | //emu.stack_pop32(false); 95 | //emu.stack_pop32(false); 96 | 97 | if str1 == str2 { 98 | emu.regs.rax = 0; 99 | } else { 100 | emu.regs.rax = 0xffffffff; 101 | } 102 | } 103 | 104 | fn fopen(emu: &mut emu::Emu) { 105 | let filepath_ptr = emu 106 | .maps 107 | .read_dword(emu.regs.get_esp()) 108 | .expect("msvcrt!fopen error reading filepath pointer") as u64; 109 | let mode_ptr = emu 110 | .maps 111 | .read_dword(emu.regs.get_esp() + 4) 112 | .expect("msvcrt!fopen error reading mode pointer") as u64; 113 | 114 | let filepath = emu.maps.read_string(filepath_ptr); 115 | let mode = emu.maps.read_string(mode_ptr); 116 | 117 | log::info!( 118 | "{}** {} msvcrt!fopen `{}` fmt:`{}` {}", 119 | emu.colors.light_red, emu.pos, filepath, mode, emu.colors.nc 120 | ); 121 | 122 | //emu.stack_pop32(false); 123 | //emu.stack_pop32(false); 124 | 125 | emu.regs.rax = helper::handler_create(&filepath); 126 | } 127 | 128 | fn fwrite(emu: &mut emu::Emu) { 129 | let buff_ptr = emu 130 | .maps 131 | .read_dword(emu.regs.get_esp()) 132 | .expect("msvcrt!fwrite error reading buff_ptr") as u64; 133 | let size = emu 134 | .maps 135 | .read_dword(emu.regs.get_esp() + 4) 136 | .expect("msvcrt!fwrite error reading size"); 137 | let nemb = emu 138 | .maps 139 | .read_dword(emu.regs.get_esp() + 8) 140 | .expect("msvcrt!fwrite error reading nemb"); 141 | let file = emu 142 | .maps 143 | .read_dword(emu.regs.get_esp() + 12) 144 | .expect("msvcrt!fwrite error reading FILE *"); 145 | 146 | let filename = helper::handler_get_uri(file as u64); 147 | 148 | /*for _ in 0..4 { 149 | emu.stack_pop32(false); 150 | }*/ 151 | log::info!( 152 | "{}** {} msvcrt!fwrite `{}` 0x{:x} {} {}", 153 | emu.colors.light_red, emu.pos, filename, buff_ptr, size, emu.colors.nc 154 | ); 155 | 156 | emu.regs.rax = size as u64; 157 | } 158 | 159 | fn fflush(emu: &mut emu::Emu) { 160 | let file = emu 161 | .maps 162 | .read_dword(emu.regs.get_esp()) 163 | .expect("msvcrt!fflush error getting FILE *"); 164 | 165 | let filename = helper::handler_get_uri(file as u64); 166 | 167 | log::info!( 168 | "{}** {} msvcrt!fflush `{}` {}", 169 | emu.colors.light_red, emu.pos, filename, emu.colors.nc 170 | ); 171 | 172 | //emu.stack_pop32(false); 173 | 174 | emu.regs.rax = 1; 175 | } 176 | 177 | fn fclose(emu: &mut emu::Emu) { 178 | let file = emu 179 | .maps 180 | .read_dword(emu.regs.get_esp()) 181 | .expect("msvcrt!fclose error getting FILE *"); 182 | 183 | let filename = helper::handler_get_uri(file as u64); 184 | 185 | log::info!( 186 | "{}** {} msvcrt!fclose `{}` {}", 187 | emu.colors.light_red, emu.pos, filename, emu.colors.nc 188 | ); 189 | 190 | //emu.stack_pop32(false); 191 | 192 | emu.regs.rax = 1; 193 | } 194 | 195 | fn __p___argv(emu: &mut emu::Emu) { 196 | log::info!( 197 | "{}** {} msvcrt!__p___argc {}", 198 | emu.colors.light_red, emu.pos, emu.colors.nc 199 | ); 200 | emu.regs.rax = 0; 201 | } 202 | 203 | fn __p___argc(emu: &mut emu::Emu) { 204 | 205 | let args = match emu.maps.get_map_by_name("args") { 206 | Some(a) => a, 207 | None => { 208 | let addr = emu.maps.alloc(1024).expect("out of memory"); 209 | emu.maps.create_map("args", addr, 1024).expect("cannot create args map") 210 | } 211 | }; 212 | 213 | log::info!( 214 | "{}** {} msvcrt!__p___argc {} {}", 215 | emu.colors.light_red, emu.pos, args.get_base(), emu.colors.nc 216 | ); 217 | 218 | emu.regs.rax = args.get_base(); 219 | } 220 | 221 | fn malloc(emu: &mut emu::Emu) { 222 | let size = emu.maps.read_dword(emu.regs.get_esp()) 223 | .expect("msvcrt!malloc error reading size") as u64; 224 | 225 | if size > 0 { 226 | let base = emu.maps.alloc(size) 227 | .expect("msvcrt!malloc out of memory"); 228 | 229 | emu.maps.create_map(&format!("alloc_{:x}", base), base, size) 230 | .expect("msvcrt!malloc cannot create map"); 231 | 232 | log::info!("{}** {} msvcrt!malloc sz: {} addr: 0x{:x} {}", 233 | emu.colors.light_red, emu.pos, size, base, emu.colors.nc); 234 | 235 | emu.regs.rax = base; 236 | } else { 237 | emu.regs.rax = 0x1337; // weird msvcrt has to return a random unallocated pointer, and the program has to do free() on it 238 | } 239 | } 240 | 241 | fn __p__acmdln(emu: &mut emu::Emu) { 242 | 243 | log::info!( 244 | "{}** {} msvcrt!__p___argc {}", 245 | emu.colors.light_red, emu.pos, emu.colors.nc 246 | ); 247 | emu.regs.rax = 0; 248 | } 249 | 250 | fn _onexit(emu: &mut emu::Emu) { 251 | 252 | let fptr = emu.maps.read_dword(emu.regs.get_esp()) 253 | .expect("msvcrt!_onexit") as u64; 254 | 255 | log::info!( 256 | "{}** {} msvcrt!_onexit 0x{:x} {}", 257 | emu.colors.light_red, emu.pos, fptr, emu.colors.nc 258 | ); 259 | 260 | emu.regs.rax = fptr; 261 | //emu.stack_pop32(false); 262 | } 263 | 264 | fn _lock(emu: &mut emu::Emu) { 265 | 266 | let lock_num = emu.maps.read_dword(emu.regs.get_esp()) 267 | .expect("msvcrt!_lock"); 268 | 269 | log::info!( 270 | "{}** {} msvcrt!_lock {} {}", 271 | emu.colors.light_red, emu.pos, lock_num, emu.colors.nc 272 | ); 273 | 274 | emu.regs.rax = 1; 275 | //emu.stack_pop32(false); 276 | } 277 | 278 | fn free(emu: &mut emu::Emu) { 279 | let addr = emu.maps.read_dword(emu.regs.get_esp()) 280 | .expect("msvcrt!free error reading addr"); 281 | 282 | log::info!( 283 | "{}** {} msvcrt!free 0x{:x} {}", 284 | emu.colors.light_red, emu.pos, addr, emu.colors.nc 285 | ); 286 | } 287 | 288 | fn realloc(emu: &mut emu::Emu) { 289 | 290 | let addr = emu.maps.read_dword(emu.regs.get_esp()) 291 | .expect("msvcrt!realloc error reading addr") as u64; 292 | let size = emu.maps.read_dword(emu.regs.get_esp() + 4) 293 | .expect("msvcrt!realloc error reading size") as u64; 294 | 295 | if addr == 0 { 296 | if size == 0 { 297 | emu.regs.rax = 0; 298 | return; 299 | } else { 300 | let base = emu.maps.alloc(size) 301 | .expect("msvcrt!malloc out of memory"); 302 | 303 | emu.maps.create_map(&format!("alloc_{:x}", base), base, size) 304 | .expect("msvcrt!malloc cannot create map"); 305 | 306 | log::info!("{}** {} msvcrt!realloc 0x{:x} {} =0x{:x} {}", 307 | emu.colors.light_red, emu.pos, addr, size, base, emu.colors.nc); 308 | 309 | emu.regs.rax = base; 310 | return; 311 | } 312 | } 313 | 314 | if size == 0 { 315 | log::info!("{}** {} msvcrt!realloc 0x{:x} {} =0x1337 {}", 316 | emu.colors.light_red, emu.pos, addr, size, emu.colors.nc); 317 | 318 | emu.regs.rax = 0x1337; // weird msvcrt has to return a random unallocated pointer, and the program has to do free() on it 319 | return; 320 | } 321 | 322 | let mem = emu.maps.get_mem_by_addr(addr).expect("msvcrt!realloc error getting mem"); 323 | let prev_size = mem.size(); 324 | 325 | let new_addr = emu.maps.alloc(size) 326 | .expect("msvcrt!realloc out of memory"); 327 | 328 | emu.maps.create_map(&format!("alloc_{:x}", new_addr), new_addr, size) 329 | .expect("msvcrt!realloc cannot create map"); 330 | 331 | emu.maps.memcpy(new_addr, addr, prev_size); 332 | emu.maps.dealloc(addr); 333 | 334 | log::info!( 335 | "{}** {} msvcrt!realloc 0x{:x} {} =0x{:x} {}", 336 | emu.colors.light_red, emu.pos, addr, size, new_addr, emu.colors.nc 337 | ); 338 | 339 | emu.regs.rax = new_addr; 340 | } 341 | 342 | fn strtok(emu: &mut emu::Emu) { 343 | let str_ptr = emu.maps.read_dword(emu.regs.get_esp()) 344 | .expect("msvcrt!strtok error reading str_ptr"); 345 | 346 | let delim_ptr = emu.maps.read_dword(emu.regs.get_esp() + 4) 347 | .expect("msvcrt!strtok error reading delim"); 348 | 349 | let str = emu.maps.read_string(str_ptr as u64); 350 | let delim = emu.maps.read_string(delim_ptr as u64); 351 | 352 | log::info!("{}** {} msvcrt!strtok `{}` `{}` {}", 353 | emu.colors.light_red, emu.pos, str, delim, emu.colors.nc); 354 | 355 | emu.regs.rax = 0; 356 | } -------------------------------------------------------------------------------- /src/emu/winapi32/oleaut32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu::winapi32::kernel32; 2 | //use crate::emu::winapi32::helper; 3 | use crate::emu; 4 | 5 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 6 | let api = kernel32::guess_api_name(emu, addr); 7 | match api.as_str() { 8 | "SysAllocStringLen" => SysAllocStringLen(emu), 9 | "SysFreeString" => SysFreeString(emu), 10 | 11 | _ => { 12 | log::info!("calling unimplemented oleaut32 API 0x{:x} {}", addr, api); 13 | return api; 14 | } 15 | } 16 | 17 | return String::new(); 18 | } 19 | 20 | fn SysAllocStringLen(emu: &mut emu::Emu) { 21 | let str_ptr = emu 22 | .maps 23 | .read_dword(emu.regs.get_esp()) 24 | .expect("oleaut32!SysAllocStringLen cannot read str_ptr") as u64; 25 | let mut size = emu 26 | .maps 27 | .read_dword(emu.regs.get_esp() + 4) 28 | .expect("oleaut32!SysAllocStringLen cannot read size") as u64; 29 | 30 | if size == 0xffffffff { 31 | size = 1024; 32 | } 33 | size += 1; // null byte 34 | size += 8; // metadata 35 | 36 | let base = emu 37 | .maps 38 | .alloc(size + 8) 39 | .expect("oleaut32!SysAllocStringLen out of memory"); 40 | let name = format!("alloc_{:x}", base + 8); 41 | emu.maps.create_map(&name, base, size); 42 | emu.maps.memcpy(base + 8, str_ptr, size as usize - 1); 43 | 44 | log::info!( 45 | "{}** {} oleaut32!SysAllocStringLen ={} {} {}", 46 | emu.colors.light_red, 47 | emu.pos, 48 | name, 49 | size - 8, 50 | emu.colors.nc 51 | ); 52 | 53 | for _ in 0..2 { 54 | emu.stack_pop32(false); 55 | } 56 | 57 | emu.regs.rax = base + 8; 58 | } 59 | 60 | fn SysFreeString(emu: &mut emu::Emu) { 61 | let str_ptr = emu 62 | .maps 63 | .read_dword(emu.regs.get_esp()) 64 | .expect("oleaut32!SysFreeString cannot read host_port") as u64; 65 | 66 | log::info!( 67 | "{}** {} oleaut32!SysFreeString 0x{:x} {}", 68 | emu.colors.light_red, emu.pos, str_ptr, emu.colors.nc 69 | ); 70 | 71 | //emu.maps.free(&format!("alloc_{:x}", str_ptr)); 72 | 73 | emu.stack_pop32(false); 74 | } 75 | -------------------------------------------------------------------------------- /src/emu/winapi32/shlwapi.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::winapi32::kernel32; 3 | //use crate::emu::winapi32::helper; 4 | //use crate::emu::endpoint; 5 | 6 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 7 | let api = kernel32::guess_api_name(emu, addr); 8 | match api.as_str() { 9 | _ => { 10 | log::info!("calling unimplemented shlwapi API 0x{:x} {}", addr, api); 11 | return api; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/emu/winapi32/user32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::winapi32::kernel32; 3 | 4 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 5 | let api = kernel32::guess_api_name(emu, addr); 6 | match api.as_str() { 7 | "MessageBoxA" => MessageBoxA(emu), 8 | "MessageBoxW" => MessageBoxW(emu), 9 | "GetDesktopWindow" => GetDesktopWindow(emu), 10 | "wsprintfW" => wsprintfW(emu), 11 | "GetProcessWindowStation" => GetProcessWindowStation(emu), 12 | "GetUserObjectInformationW" => GetUserObjectInformationW(emu), 13 | "CharLowerW" => CharLowerW(emu), 14 | "wsprintfA" => wsprintfA(emu), 15 | _ => { 16 | log::info!("calling unimplemented user32 API 0x{:x} {}", addr, api); 17 | return api; 18 | } 19 | } 20 | 21 | return String::new(); 22 | } 23 | 24 | fn MessageBoxA(emu: &mut emu::Emu) { 25 | let titleptr = emu 26 | .maps 27 | .read_dword(emu.regs.get_esp() + 8) 28 | .expect("user32_MessageBoxA: error reading title") as u64; 29 | let msgptr = emu 30 | .maps 31 | .read_dword(emu.regs.get_esp() + 4) 32 | .expect("user32_MessageBoxA: error reading message") as u64; 33 | let msg = emu.maps.read_string(msgptr); 34 | let title = emu.maps.read_string(titleptr); 35 | 36 | log::info!( 37 | "{}** {} user32!MessageBoxA {} {} {}", 38 | emu.colors.light_red, emu.pos, title, msg, emu.colors.nc 39 | ); 40 | 41 | emu.regs.rax = 0; 42 | for _ in 0..4 { 43 | emu.stack_pop32(false); 44 | } 45 | } 46 | 47 | fn MessageBoxW(emu: &mut emu::Emu) { 48 | let titleptr = emu 49 | .maps 50 | .read_dword(emu.regs.get_esp() + 8) 51 | .expect("user32_MessageBoxA: error reading title") as u64; 52 | let msgptr = emu 53 | .maps 54 | .read_dword(emu.regs.get_esp() + 4) 55 | .expect("user32_MessageBoxA: error reading message") as u64; 56 | let msg = emu.maps.read_wide_string(msgptr); 57 | let title = emu.maps.read_wide_string(titleptr); 58 | 59 | log::info!( 60 | "{}** {} user32!MessageBoxW {} {} {}", 61 | emu.colors.light_red, emu.pos, title, msg, emu.colors.nc 62 | ); 63 | 64 | emu.regs.rax = 0; 65 | for _ in 0..4 { 66 | emu.stack_pop32(false); 67 | } 68 | } 69 | 70 | fn GetDesktopWindow(emu: &mut emu::Emu) { 71 | log::info!( 72 | "{}** {} user32!GetDesktopWindow {}", 73 | emu.colors.light_red, emu.pos, emu.colors.nc 74 | ); 75 | //emu.regs.rax = 0x11223344; // current window handle 76 | emu.regs.rax = 0; // no windows handler is more stealthy 77 | } 78 | 79 | fn wsprintfW(emu: &mut emu::Emu) {} 80 | 81 | fn GetProcessWindowStation(emu: &mut emu::Emu) { 82 | log::info!( 83 | "{}** {} user32!GetProcessWindowStation {}", 84 | emu.colors.light_red, emu.pos, emu.colors.nc 85 | ); 86 | 87 | emu.regs.rax = 0x1337; // get handler 88 | } 89 | 90 | fn GetUserObjectInformationW(emu: &mut emu::Emu) { 91 | let hndl = emu 92 | .maps 93 | .read_dword(emu.regs.get_esp()) 94 | .expect("user32!GetUserObjectInformationW: error reading title") as u64; 95 | let nidx = emu 96 | .maps 97 | .read_dword(emu.regs.get_esp()) 98 | .expect("user32!GetUserObjectInformationW: error reading title") as u64; 99 | let out_vinfo = emu 100 | .maps 101 | .read_dword(emu.regs.get_esp()) 102 | .expect("user32!GetUserObjectInformationW: error reading title") as u64; 103 | let nlen = emu 104 | .maps 105 | .read_dword(emu.regs.get_esp()) 106 | .expect("user32!GetUserObjectInformationW: error reading title") as u64; 107 | let out_len = emu 108 | .maps 109 | .read_dword(emu.regs.get_esp()) 110 | .expect("user32!GetUserObjectInformationW: error reading title") as u64; 111 | 112 | 113 | 114 | log::info!( 115 | "{}** {} user32!GetUserObjectInformationW {}", 116 | emu.colors.light_red, emu.pos, emu.colors.nc 117 | ); 118 | 119 | for _ in 0..5 { 120 | emu.stack_pop32(false); 121 | } 122 | 123 | emu.regs.rax = 1; // get handler 124 | } 125 | 126 | fn CharLowerW(emu: &mut emu::Emu) { 127 | let ptr_str = emu 128 | .maps 129 | .read_dword(emu.regs.get_esp()) 130 | .expect("user32!CharLowerW: error reading param") as u64; 131 | 132 | let s = emu.maps.read_wide_string(ptr_str); 133 | 134 | log::info!( 135 | "{}** {} user32!CharLowerW(`{}`) {}", 136 | emu.colors.light_red, emu.pos, s, emu.colors.nc 137 | ); 138 | 139 | emu.maps.write_wide_string(ptr_str, &s.to_lowercase()); 140 | 141 | emu.stack_pop32(false); 142 | emu.regs.rax = ptr_str; 143 | } 144 | 145 | fn wsprintfA(emu: &mut emu::Emu) { 146 | let out = emu 147 | .maps 148 | .read_dword(emu.regs.get_esp()) 149 | .expect("user32!wsprintfA: error reading out") as u64; 150 | let in_fmt = emu 151 | .maps 152 | .read_dword(emu.regs.get_esp() + 4) 153 | .expect("user32!wsprintfA: error reading in_fmt") as u64; 154 | let mut multiple = emu 155 | .maps 156 | .read_dword(emu.regs.get_esp() + 8) 157 | .expect("user32!wsprintfA: error reading multiple") as u64; 158 | 159 | let fmt = emu.maps.read_string(in_fmt); 160 | let mut args = Vec::new(); 161 | let mut chars = fmt.chars().peekable(); 162 | let mut arg_index = 0; 163 | let mut result = String::new(); 164 | 165 | while let Some(arg) = emu.maps.read_dword(multiple) { 166 | args.push(arg as u64); 167 | multiple += 4; 168 | } 169 | 170 | while let Some(c) = chars.next() { 171 | if c == '%' { 172 | if chars.peek() == Some(&'%') { 173 | result.push('%'); 174 | chars.next(); 175 | } else if arg_index < args.len() { 176 | let specifier = chars.next(); 177 | match specifier { 178 | Some('d') => result.push_str(&format!("{}", args[arg_index] as i32)), 179 | Some('u') => result.push_str(&format!("{}", args[arg_index])), 180 | Some('x') => result.push_str(&format!("{:x}", args[arg_index])), 181 | Some('X') => result.push_str(&format!("{:X}", args[arg_index])), 182 | Some('s') => { 183 | let addr = args[arg_index]; 184 | let s = emu.maps.read_string(addr); 185 | if s != "" { 186 | result.push_str(&s); 187 | } else { 188 | result.push_str(""); 189 | } 190 | } 191 | Some('c') => result.push(args[arg_index] as u8 as char), 192 | _ => result.push_str(""), 193 | } 194 | arg_index += 1; 195 | } else { 196 | result.push_str(""); 197 | } 198 | } else { 199 | result.push(c); 200 | } 201 | } 202 | 203 | emu.maps 204 | .write_string(out, &result); 205 | 206 | 207 | log::info!( 208 | "{}** {} user32!wsprintfA fmt:`{}` out:`{}` {}", 209 | emu.colors.light_red, emu.pos, fmt, &result, emu.colors.nc 210 | ); 211 | 212 | emu.stack_pop32(false); 213 | emu.stack_pop32(false); 214 | emu.stack_pop32(false); 215 | 216 | emu.regs.rax = result.len() as u64; 217 | } -------------------------------------------------------------------------------- /src/emu/winapi32/wincrt.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | //use crate::emu::constants::*; 3 | //use crate::emu::winapi32::helper; 4 | use crate::emu::winapi32::kernel32; 5 | 6 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 7 | let api = kernel32::guess_api_name(emu, addr); 8 | match api.as_str() { 9 | "_set_invalid_parameter_handler" => set_invalid_parameter_handler(emu), 10 | 11 | 12 | _ => { 13 | log::info!("calling unimplemented wincrt API 0x{:x} {}", addr, api); 14 | return api; 15 | } 16 | } 17 | 18 | return String::new(); 19 | } 20 | 21 | fn set_invalid_parameter_handler(emu: &mut emu::Emu) { 22 | log::info!("{}** {} wincrt!_set_invalid_parameter_handler {}", emu.colors.light_red, emu.pos, emu.colors.nc); 23 | emu.regs.rax = 0; 24 | } 25 | -------------------------------------------------------------------------------- /src/emu/winapi32/ws2_32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | //use crate::emu::endpoint; 3 | use crate::emu::winapi32::helper; 4 | use crate::emu::winapi32::kernel32; 5 | 6 | use lazy_static::lazy_static; 7 | use std::sync::Mutex; 8 | 9 | pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { 10 | let api = kernel32::guess_api_name(emu, addr); 11 | match api.as_str() { 12 | "WsaStartup" => WsaStartup(emu), 13 | "WsaSocketA" => WsaSocketA(emu), 14 | "socket" => socket(emu), 15 | "WsaHtons" => WsaHtons(emu), 16 | "htons" => htons(emu), 17 | "inet_addr" => inet_addr(emu), 18 | "connect" => connect(emu), 19 | "recv" => recv(emu), 20 | "send" => send(emu), 21 | "bind" => bind(emu), 22 | "listen" => listen(emu), 23 | "accept" => accept(emu), 24 | "closesocket" => closesocket(emu), 25 | "setsockopt" => setsockopt(emu), 26 | "getsockopt" => getsockopt(emu), 27 | "WsaAccept" => WsaAccept(emu), 28 | 29 | /* 30 | 0x774834b5 => sendto(emu), 31 | 0x7748b6dc => recvfrom(emu), 32 | 0x77487089 => WsaRecv(emu), 33 | 0x7748cba6 => WsaRecvFrom(emu), 34 | 0x7748cc3f => WsaConnect(emu), 35 | */ 36 | _ => { 37 | log::info!("calling unimplemented ws2_32 API 0x{:x} {}", addr, api); 38 | return api; 39 | } 40 | } 41 | 42 | return String::new(); 43 | } 44 | 45 | lazy_static! { 46 | static ref COUNT_SEND: Mutex = Mutex::new(0); 47 | static ref COUNT_RECV: Mutex = Mutex::new(0); 48 | } 49 | 50 | fn WsaStartup(emu: &mut emu::Emu) { 51 | log::info!( 52 | "{}** {} ws2_32!WsaStartup {}", 53 | emu.colors.light_red, emu.pos, emu.colors.nc 54 | ); 55 | 56 | for _ in 0..2 { 57 | emu.stack_pop32(false); 58 | } 59 | emu.regs.rax = 0; 60 | } 61 | 62 | fn WsaSocketA(emu: &mut emu::Emu) { 63 | log::info!( 64 | "{}** {} ws2_32!WsaSocketA {}", 65 | emu.colors.light_red, emu.pos, emu.colors.nc 66 | ); 67 | 68 | for _ in 0..6 { 69 | emu.stack_pop32(false); 70 | } 71 | 72 | emu.regs.rax = helper::socket_create(); 73 | } 74 | 75 | fn socket(emu: &mut emu::Emu) { 76 | log::info!( 77 | "{}** {} ws2_32!socket {}", 78 | emu.colors.light_red, emu.pos, emu.colors.nc 79 | ); 80 | 81 | for _ in 0..3 { 82 | emu.stack_pop32(false); 83 | } 84 | 85 | emu.regs.rax = helper::socket_create(); 86 | } 87 | 88 | fn WsaHtons(emu: &mut emu::Emu) { 89 | let host_port = emu 90 | .maps 91 | .read_dword(emu.regs.get_esp() + 4) 92 | .expect("ws2_32!WsaHtons cannot read host_port"); 93 | let out_port = emu 94 | .maps 95 | .read_dword(emu.regs.get_esp() + 8) 96 | .expect("ws2_32!WsaHtons cannot read out_port"); 97 | 98 | log::info!( 99 | "{}** {} ws2_32!WsaHtons {} {}", 100 | emu.colors.light_red, emu.pos, host_port, emu.colors.nc 101 | ); 102 | 103 | for _ in 0..3 { 104 | emu.stack_pop32(false); 105 | } 106 | 107 | //TODO: implement this 108 | 109 | emu.regs.rax = 0; 110 | } 111 | 112 | fn htons(emu: &mut emu::Emu) { 113 | let port: u16 = match emu.maps.read_word(emu.regs.get_esp()) { 114 | Some(p) => p, 115 | None => 0, 116 | }; 117 | 118 | log::info!( 119 | "{}** {} ws2_32!htons port: {} {}", 120 | emu.colors.light_red, emu.pos, port, emu.colors.nc 121 | ); 122 | 123 | emu.stack_pop32(false); 124 | emu.regs.rax = port.to_be() as u64; 125 | } 126 | 127 | fn inet_addr(emu: &mut emu::Emu) { 128 | let addr = emu 129 | .maps 130 | .read_dword(emu.regs.get_esp()) 131 | .expect("ws2_32!inet_addr: error reading addr"); 132 | 133 | log::info!( 134 | "{}** {} ws2_32!inet_addr {}", 135 | emu.colors.light_red, emu.pos, emu.colors.nc 136 | ); 137 | 138 | emu.stack_pop32(false); 139 | emu.regs.rax = 0; 140 | } 141 | 142 | fn connect(emu: &mut emu::Emu) { 143 | let sock = emu 144 | .maps 145 | .read_dword(emu.regs.get_esp()) 146 | .expect("ws2_32!connect: error reading sock") as u64; 147 | let sockaddr_ptr = emu 148 | .maps 149 | .read_dword(emu.regs.get_esp() + 4) 150 | .expect("ws2_32!connect: error reading sockaddr ptr") as u64; 151 | //let sockaddr = emu.maps.read_bytes(sockaddr_ptr, 8); 152 | let family: u16 = emu 153 | .maps 154 | .read_word(sockaddr_ptr) 155 | .expect("ws2_32!connect: error reading family"); 156 | let port: u16 = emu 157 | .maps 158 | .read_word(sockaddr_ptr + 2) 159 | .expect("ws2_32!connect: error reading port") 160 | .to_be(); 161 | let ip: u32 = emu 162 | .maps 163 | .read_dword(sockaddr_ptr + 4) 164 | .expect("ws2_32!connect: error reading ip"); 165 | 166 | let sip = format!( 167 | "{}.{}.{}.{}", 168 | ip & 0xff, 169 | (ip & 0xff00) >> 8, 170 | (ip & 0xff0000) >> 16, 171 | (ip & 0xff000000) >> 24 172 | ); 173 | log::info!( 174 | "{}** {} ws2_32!connect family: {} {}:{} {}", 175 | emu.colors.light_red, emu.pos, family, sip, port, emu.colors.nc 176 | ); 177 | 178 | for _ in 0..3 { 179 | emu.stack_pop32(false); 180 | } 181 | 182 | if emu.cfg.endpoint { 183 | /* 184 | if endpoint::sock_connect(sip.as_str(), port) { 185 | log::info!("\tconnected to the endpoint."); 186 | } else { 187 | log::info!("\tcannot connect. dont use -e"); 188 | }*/ 189 | emu.regs.rax = 0; 190 | } else { 191 | // offline mode 192 | 193 | if !helper::socket_exist(sock) { 194 | log::info!("\tinvalid socket."); 195 | emu.regs.rax = 1; 196 | } else { 197 | emu.regs.rax = 0; 198 | } 199 | } 200 | } 201 | 202 | fn recv(emu: &mut emu::Emu) { 203 | let sock = emu 204 | .maps 205 | .read_dword(emu.regs.get_esp()) 206 | .expect("ws2_32!recv: error reading sock") as u64; 207 | let buff = emu 208 | .maps 209 | .read_dword(emu.regs.get_esp() + 4) 210 | .expect("ws2_32!recv: error reading buff") as u64; 211 | let mut len = emu 212 | .maps 213 | .read_dword(emu.regs.get_esp() + 8) 214 | .expect("ws2_32!recv: error reading len") as u64; 215 | let flags = emu 216 | .maps 217 | .read_dword(emu.regs.get_esp() + 12) 218 | .expect("ws2_32!recv: error reading flags") as u64; 219 | 220 | log::info!( 221 | "{}** {} ws2_32!recv buff: 0x{:x} sz: {} {}", 222 | emu.colors.light_red, emu.pos, buff, len, emu.colors.nc 223 | ); 224 | 225 | for _ in 0..4 { 226 | emu.stack_pop32(false); 227 | } 228 | 229 | if !helper::socket_exist(sock) { 230 | log::info!("\tinvalid socket."); 231 | emu.regs.rax = 1; 232 | return; 233 | } 234 | 235 | if emu.cfg.endpoint { 236 | /* 237 | let mut rbuff: Vec = vec![0; len as usize]; 238 | let n = endpoint::sock_recv(&mut rbuff); 239 | 240 | emu.maps.write_buffer(buff, &rbuff); 241 | 242 | log::info!("\nreceived {} bytes from the endpoint.", n); 243 | emu.regs.rax = n as u64; 244 | */ 245 | } else { 246 | let mut count_recv = COUNT_RECV.lock().unwrap(); 247 | *count_recv += 1; 248 | if *count_recv > 3 { 249 | len = 0; // finish the recv loop 250 | } 251 | 252 | if helper::socket_exist(sock) { 253 | //emu.maps.write_spaced_bytes(buff, "6c 73 0d 0a".to_string()); // send a ls\r\n 254 | if len == 4 { 255 | emu.maps.write_dword(buff, 0x0100); // probably expect a size 256 | } else { 257 | emu.maps.memset(buff, 0x90, len as usize); 258 | } 259 | 260 | emu.regs.rax = len; 261 | } 262 | } 263 | } 264 | 265 | fn send(emu: &mut emu::Emu) { 266 | let sock = emu 267 | .maps 268 | .read_dword(emu.regs.get_esp()) 269 | .expect("ws2_32!send: error reading sock") as u64; 270 | let buff = emu 271 | .maps 272 | .read_dword(emu.regs.get_esp() + 4) 273 | .expect("ws2_32!send: error reading buff") as u64; 274 | let mut len = emu 275 | .maps 276 | .read_dword(emu.regs.get_esp() + 8) 277 | .expect("ws2_32!send: error reading len") as u64; 278 | let flags = emu 279 | .maps 280 | .read_dword(emu.regs.get_esp() + 12) 281 | .expect("ws2_32!send: error reading flags") as u64; 282 | 283 | let bytes = emu.maps.read_string_of_bytes(buff, len as usize); 284 | 285 | for _ in 0..4 { 286 | emu.stack_pop32(false); 287 | } 288 | 289 | log::info!( 290 | "{}** {} ws2_32!send {{{}}} {}", 291 | emu.colors.light_red, emu.pos, bytes, emu.colors.nc 292 | ); 293 | 294 | if !helper::socket_exist(sock) { 295 | log::info!("\tinvalid socket."); 296 | emu.regs.rax = 0; 297 | return; 298 | } 299 | 300 | if emu.cfg.endpoint { 301 | /* 302 | let buffer = emu.maps.read_buffer(buff, len as usize); 303 | let n = endpoint::sock_send(&buffer); 304 | log::info!("\tsent {} bytes.", n); 305 | emu.regs.rax = n as u64; 306 | */ 307 | } else { 308 | let mut count_send = COUNT_SEND.lock().unwrap(); 309 | *count_send += 1; 310 | if *count_send > 3 { 311 | len = 0; // finish the send loop 312 | } 313 | 314 | emu.regs.rax = len; 315 | } 316 | } 317 | 318 | fn bind(emu: &mut emu::Emu) { 319 | let sock = emu 320 | .maps 321 | .read_dword(emu.regs.get_esp()) 322 | .expect("ws2_32!send: error reading sock") as u64; 323 | let saddr = emu 324 | .maps 325 | .read_dword(emu.regs.get_esp() + 4) 326 | .expect("ws2_32!send: error reading addr") as u64; 327 | let len = emu 328 | .maps 329 | .read_dword(emu.regs.get_esp() + 8) 330 | .expect("ws2_32!send: error reading len") as u64; 331 | 332 | let family: u16 = emu 333 | .maps 334 | .read_word(saddr) 335 | .expect("ws2_32!connect: error reading family"); 336 | let port: u16 = emu 337 | .maps 338 | .read_word(saddr + 2) 339 | .expect("ws2_32!connect: error reading port"); 340 | let ip: u32 = emu 341 | .maps 342 | .read_dword(saddr + 4) 343 | .expect("ws2_32!connect: error reading ip"); 344 | 345 | let sip = format!( 346 | "{}.{}.{}.{}", 347 | ip & 0xff, 348 | (ip & 0xff00) >> 8, 349 | (ip & 0xff0000) >> 16, 350 | (ip & 0xff000000) >> 24 351 | ); 352 | 353 | log::info!( 354 | "{}** {} ws2_32!bind family: {} {}:{} {}", 355 | emu.colors.light_red, 356 | emu.pos, 357 | family, 358 | sip, 359 | port.to_be(), 360 | emu.colors.nc 361 | ); 362 | 363 | for _ in 0..3 { 364 | emu.stack_pop32(false); 365 | } 366 | 367 | if !helper::socket_exist(sock) { 368 | log::info!("\tbad socket."); 369 | emu.regs.rax = 1; 370 | } else { 371 | emu.regs.rax = 0; 372 | } 373 | } 374 | 375 | fn listen(emu: &mut emu::Emu) { 376 | let sock = emu 377 | .maps 378 | .read_dword(emu.regs.get_esp()) 379 | .expect("ws2_32!send: error reading sock") as u64; 380 | let connections = emu 381 | .maps 382 | .read_dword(emu.regs.get_esp() + 4) 383 | .expect("ws2_32!send: error reading num of connections") as u64; 384 | 385 | log::info!( 386 | "{}** {} ws2_32!listen connections: {} {}", 387 | emu.colors.light_red, emu.pos, connections, emu.colors.nc 388 | ); 389 | 390 | for _ in 0..2 { 391 | emu.stack_pop32(false); 392 | } 393 | 394 | if !helper::socket_exist(sock) { 395 | log::info!("\tinvalid socket."); 396 | emu.regs.rax = 1; 397 | } else { 398 | emu.regs.rax = 0; 399 | } 400 | } 401 | 402 | fn accept(emu: &mut emu::Emu) { 403 | let sock = emu 404 | .maps 405 | .read_dword(emu.regs.get_esp()) 406 | .expect("ws2_32!accept: error reading sock") as u64; 407 | let saddr = emu 408 | .maps 409 | .read_dword(emu.regs.get_esp() + 4) 410 | .expect("ws2_32!accept: error reading sockaddr") as u64; 411 | let len = emu 412 | .maps 413 | .read_dword(emu.regs.get_esp() + 8) 414 | .expect("ws2_32!seacceptnd: error reading len") as u64; 415 | let flags = emu 416 | .maps 417 | .read_dword(emu.regs.get_esp() + 12) 418 | .expect("ws2_32!accept: error reading flags") as u64; 419 | 420 | let bytes = emu.maps.read_string_of_bytes(saddr, len as usize); 421 | 422 | log::info!( 423 | "{}** {} ws2_32!accept connections: {} {}", 424 | emu.colors.light_red, emu.pos, bytes, emu.colors.nc 425 | ); 426 | 427 | for _ in 0..4 { 428 | emu.stack_pop32(false); 429 | } 430 | 431 | if !helper::socket_exist(sock) { 432 | log::info!("\tinvalid socket."); 433 | emu.regs.rax = 1; 434 | } else { 435 | emu.regs.rax = 0; 436 | } 437 | } 438 | 439 | fn closesocket(emu: &mut emu::Emu) { 440 | let sock = emu 441 | .maps 442 | .read_dword(emu.regs.get_esp()) 443 | .expect("ws2_32!send: error reading sock") as u64; 444 | 445 | log::info!( 446 | "{}** {} ws2_32!closesocket {}", 447 | emu.colors.light_red, emu.pos, emu.colors.nc 448 | ); 449 | 450 | helper::socket_close(sock); 451 | 452 | /* 453 | if emu.cfg.endpoint { 454 | endpoint::sock_close(); 455 | }*/ 456 | 457 | emu.stack_pop32(false); 458 | emu.regs.rax = 0; 459 | } 460 | 461 | fn setsockopt(emu: &mut emu::Emu) { 462 | let sock = emu 463 | .maps 464 | .read_dword(emu.regs.get_esp()) 465 | .expect("ws2_32!setsockopt: error reading sock") as u64; 466 | let level = emu 467 | .maps 468 | .read_dword(emu.regs.get_esp() + 4) 469 | .expect("ws2_32!setsockopt: error reading level") as u64; 470 | let optname = emu 471 | .maps 472 | .read_dword(emu.regs.get_esp() + 8) 473 | .expect("ws2_32!setsockopt: error reading optname") as u64; 474 | let optval = emu 475 | .maps 476 | .read_dword(emu.regs.get_esp() + 12) 477 | .expect("ws2_32!setsockopt: error reading optval") as u64; 478 | let optlen = emu 479 | .maps 480 | .read_dword(emu.regs.get_esp() + 16) 481 | .expect("ws2_32!setsockopt: error reading optlen") as u64; 482 | 483 | let val = match emu.maps.read_dword(optval) { 484 | Some(v) => v, 485 | None => 0, 486 | }; 487 | 488 | log::info!( 489 | "{}** {} ws2_32!setsockopt lvl: {} opt: {} val: {} {}", 490 | emu.colors.light_red, emu.pos, level, optname, val, emu.colors.nc 491 | ); 492 | 493 | for _ in 0..5 { 494 | emu.stack_pop32(false); 495 | } 496 | 497 | if !helper::socket_exist(sock) { 498 | log::info!("\tinvalid socket."); 499 | emu.regs.rax = 1; 500 | } else { 501 | emu.regs.rax = 0; 502 | } 503 | } 504 | 505 | fn getsockopt(emu: &mut emu::Emu) { 506 | let sock = emu 507 | .maps 508 | .read_dword(emu.regs.get_esp()) 509 | .expect("ws2_32!getsockopt: error reading sock") as u64; 510 | let level = emu 511 | .maps 512 | .read_dword(emu.regs.get_esp() + 4) 513 | .expect("ws2_32!getsockopt: error reading level") as u64; 514 | let optname = emu 515 | .maps 516 | .read_dword(emu.regs.get_esp() + 8) 517 | .expect("ws2_32!getsockopt: error reading optname") as u64; 518 | let optval = emu 519 | .maps 520 | .read_dword(emu.regs.get_esp() + 12) 521 | .expect("ws2_32!getsockopt: error reading optval") as u64; 522 | let optlen = emu 523 | .maps 524 | .read_dword(emu.regs.get_esp() + 16) 525 | .expect("ws2_32!getsockopt: error reading optlen") as u64; 526 | 527 | emu.maps.write_dword(optval, 1); 528 | 529 | log::info!( 530 | "{}** {} ws2_32!getsockopt lvl: {} opt: {} {}", 531 | emu.colors.light_red, emu.pos, level, optname, emu.colors.nc 532 | ); 533 | 534 | for _ in 0..5 { 535 | emu.stack_pop32(false); 536 | } 537 | 538 | if !helper::socket_exist(sock) { 539 | log::info!("\tinvalid socket."); 540 | emu.regs.rax = 1; 541 | } else { 542 | emu.regs.rax = 0; 543 | } 544 | } 545 | 546 | fn WsaAccept(emu: &mut emu::Emu) { 547 | let sock = emu 548 | .maps 549 | .read_dword(emu.regs.get_esp()) 550 | .expect("ws2_32!WsaAccept: error reading sock") as u64; 551 | let saddr = emu 552 | .maps 553 | .read_dword(emu.regs.get_esp() + 4) 554 | .expect("ws2_32!WsaAccept: error reading sockaddr") as u64; 555 | let len = emu 556 | .maps 557 | .read_dword(emu.regs.get_esp() + 8) 558 | .expect("ws2_32!WsaAccept: error reading len") as u64; 559 | let cond = emu 560 | .maps 561 | .read_dword(emu.regs.get_esp() + 12) 562 | .expect("ws2_32!WsaAccept: error reading cond") as u64; 563 | let callback = emu 564 | .maps 565 | .read_dword(emu.regs.get_esp() + 16) 566 | .expect("ws2_32!WsaAccept: error reading callback") as u64; 567 | 568 | let bytes = emu.maps.read_string_of_bytes(saddr, len as usize); 569 | 570 | log::info!( 571 | "{}** {} ws2_32!WsaAccept connections: {} callback: {} {}", 572 | emu.colors.light_red, emu.pos, bytes, callback, emu.colors.nc 573 | ); 574 | 575 | for _ in 0..5 { 576 | emu.stack_pop32(false); 577 | } 578 | 579 | if !helper::socket_exist(sock) { 580 | log::info!("\tinvalid socket."); 581 | emu.regs.rax = 1; 582 | } else { 583 | emu.regs.rax = 0; 584 | } 585 | } 586 | -------------------------------------------------------------------------------- /src/emu/winapi64.rs: -------------------------------------------------------------------------------- 1 | mod advapi32; 2 | mod comctl64; 3 | mod dnsapi; 4 | pub mod kernel32; 5 | mod ntdll; 6 | mod shell32; 7 | mod user32; 8 | mod winhttp; 9 | mod wininet; 10 | mod ws2_32; 11 | mod shlwapi; 12 | mod kernelbase; 13 | 14 | use crate::emu; 15 | 16 | pub fn gateway(addr: u64, name: String, emu: &mut emu::Emu) { 17 | log::info!("winapi64::gateway called with addr: 0x{:x}, name: {}", addr, name); 18 | 19 | let unimplemented_api = match name.as_str() { 20 | "kernel32.text" => kernel32::gateway(addr, emu), 21 | "kernel32.rdata" => kernel32::gateway(addr, emu), 22 | "ntdll.text" => ntdll::gateway(addr, emu), 23 | "user32.text" => user32::gateway(addr, emu), 24 | "ws2_32.text" => ws2_32::gateway(addr, emu), 25 | "wininet.text" => wininet::gateway(addr, emu), 26 | "advapi32.text" => advapi32::gateway(addr, emu), 27 | "winhttp.text" => winhttp::gateway(addr, emu), 28 | "dnsapi.text" => dnsapi::gateway(addr, emu), 29 | "comctl32.text" => comctl64::gateway(addr, emu), 30 | "shell32.text" => shell32::gateway(addr, emu), 31 | "shlwapi.text" => shlwapi::gateway(addr, emu), 32 | "kernelbase.text" => kernelbase::gateway(addr, emu), 33 | "not_loaded" => { 34 | emu.pe64.as_ref().unwrap().import_addr_to_name(addr) 35 | } 36 | _ => panic!("/!\\ trying to execute on {} at 0x{:x}", name, addr), 37 | }; 38 | 39 | if unimplemented_api.len() > 0 { 40 | log::info!( 41 | "{}({}, {}, {}, {}) (unimplemented)", 42 | unimplemented_api, emu.regs.rcx, emu.regs.rdx, emu.regs.r8, emu.regs.r9 43 | ); 44 | 45 | emu.regs.rax = 1; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/emu/winapi64/advapi32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::constants; 3 | use crate::emu::winapi32::helper; 4 | 5 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 6 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 7 | match apiname.as_str() { 8 | "StartServiceCtrlDispatcherA" => StartServiceCtrlDispatcherA(emu), 9 | "StartServiceCtrlDispatcherW" => StartServiceCtrlDispatcherW(emu), 10 | "RegOpenKeyExA" => RegOpenKeyExA(emu), 11 | "RegQueryValueExA" => RegQueryValueExA(emu), 12 | "RegCloseKey" => RegCloseKey(emu), 13 | 14 | _ => { 15 | log::info!( 16 | "calling unimplemented advapi32 API 0x{:x} {}", 17 | addr, apiname 18 | ); 19 | return apiname; 20 | } 21 | } 22 | 23 | return String::new(); 24 | } 25 | 26 | fn StartServiceCtrlDispatcherA(emu: &mut emu::Emu) { 27 | let service_table_entry_ptr = emu 28 | .maps 29 | .read_dword(emu.regs.get_esp()) 30 | .expect("advapi32!StartServiceCtrlDispatcherA error reading service_table_entry pointer"); 31 | 32 | let service_name = emu 33 | .maps 34 | .read_dword(service_table_entry_ptr as u64) 35 | .expect("advapi32!StartServiceCtrlDispatcherA error reading service_name"); 36 | let service_name = emu 37 | .maps 38 | .read_dword((service_table_entry_ptr + 4) as u64) 39 | .expect("advapi32!StartServiceCtrlDispatcherA error reading service_name"); 40 | 41 | emu.regs.set_eax(1); 42 | } 43 | 44 | fn StartServiceCtrlDispatcherW(emu: &mut emu::Emu) { 45 | let service_table_entry_ptr = emu 46 | .maps 47 | .read_dword(emu.regs.get_esp()) 48 | .expect("advapi32!StartServiceCtrlDispatcherW error reading service_table_entry pointer"); 49 | 50 | emu.regs.set_eax(1); 51 | } 52 | 53 | fn RegOpenKeyExA(emu: &mut emu::Emu) { 54 | let hkey = emu.regs.rcx; 55 | let subkey_ptr = emu.regs.rdx; 56 | let opts = emu.regs.r8; 57 | let result = emu.regs.r9; 58 | 59 | let subkey = emu.maps.read_string(subkey_ptr); 60 | 61 | log::info!( 62 | "{}** {} advapi32!RegOpenKeyExA {} {}", 63 | emu.colors.light_red, emu.pos, subkey, emu.colors.nc 64 | ); 65 | 66 | emu.maps 67 | .write_qword(result, helper::handler_create(&subkey)); 68 | emu.regs.rax = constants::ERROR_SUCCESS; 69 | } 70 | 71 | fn RegCloseKey(emu: &mut emu::Emu) { 72 | let hkey = emu.regs.rcx; 73 | 74 | log::info!( 75 | "{}** {} advapi32!RegCloseKey {}", 76 | emu.colors.light_red, emu.pos, emu.colors.nc 77 | ); 78 | 79 | helper::handler_close(hkey); 80 | 81 | emu.regs.rax = constants::ERROR_SUCCESS; 82 | } 83 | 84 | fn RegQueryValueExA(emu: &mut emu::Emu) { 85 | let hkey = emu.regs.rcx; 86 | let value_ptr = emu.regs.rdx; 87 | let reserved = emu.regs.r8; 88 | let typ_out = emu.regs.r9; 89 | let data_out = emu 90 | .maps 91 | .read_qword(emu.regs.rsp) 92 | .expect("error reading api aparam"); 93 | let datasz_out = emu 94 | .maps 95 | .read_qword(emu.regs.rsp + 8) 96 | .expect("error reading api param"); 97 | 98 | let value = emu.maps.read_string(value_ptr); 99 | 100 | log::info!( 101 | "{}** {} advapi32!RegQueryValueExA {} {}", 102 | emu.colors.light_red, emu.pos, value, emu.colors.nc 103 | ); 104 | 105 | emu.maps.write_string(data_out, "some_random_reg_contents"); 106 | emu.maps.write_qword(datasz_out, 24); 107 | emu.regs.rax = constants::ERROR_SUCCESS; 108 | } 109 | -------------------------------------------------------------------------------- /src/emu/winapi64/comctl64.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | 3 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 4 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 5 | match apiname.as_str() { 6 | _ => { 7 | log::info!("calling unimplemented comctl32 API 0x{:x} {}", addr, apiname); 8 | return apiname; 9 | } 10 | } 11 | 12 | // return String::new(); 13 | } 14 | -------------------------------------------------------------------------------- /src/emu/winapi64/dnsapi.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | 3 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 4 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 5 | match apiname.as_str() { 6 | /*0x77733553 => StartServiceCtrlDispatcherA(emu), 7 | 0x776fa965 => StartServiceCtrlDispatcherW(emu),*/ 8 | _ => { 9 | log::info!("calling unimplemented winhttp API 0x{:x} {}", addr, apiname); 10 | return apiname; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/emu/winapi64/kernelbase.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | //use crate::emu::constants; 3 | //use crate::emu::winapi32::helper; 4 | 5 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 6 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 7 | match apiname.as_str() { 8 | 9 | "PathCombineA" => PathCombineA(emu), 10 | "IsCharAlphaNumericA" => IsCharAlphaNumericA(emu), 11 | "GetTokenInformation" => GetTokenInformation(emu), 12 | 13 | _ => { 14 | log::info!( 15 | "calling unimplemented kernelbase API 0x{:x} {}", 16 | addr, apiname 17 | ); 18 | return apiname; 19 | } 20 | } 21 | 22 | return String::new(); 23 | } 24 | 25 | pub fn PathCombineA(emu: &mut emu::Emu) { 26 | let dst: u64 = emu.regs.rcx; 27 | let path1 = emu.maps.read_string(emu.regs.rdx); 28 | let path2 = emu.maps.read_string(emu.regs.r8); 29 | 30 | log::info!( 31 | "{}** {} kernelbase!PathCombineA path1: {} path2: {} {}", 32 | emu.colors.light_red, emu.pos, path1, path2, emu.colors.nc 33 | ); 34 | 35 | if dst != 0 && path1 != "" && path2 != "" { 36 | emu.maps.write_string(dst, &format!("{}\\{}", path1, path2)); 37 | } 38 | 39 | emu.regs.rax = dst; 40 | } 41 | 42 | pub fn IsCharAlphaNumericA(emu: &mut emu::Emu) { 43 | let c = emu.regs.rcx as u8 as char; 44 | 45 | log::info!( 46 | "{}** {} kernelbase!IsCharAlphaNumericA char: {} {}", 47 | emu.colors.light_red, emu.pos, c, emu.colors.nc 48 | ); 49 | 50 | emu.regs.rax = if c.is_ascii_alphanumeric() { 1 } else { 0 }; 51 | } 52 | 53 | pub fn GetTokenInformation(emu: &mut emu::Emu) { 54 | let token_handle = emu.regs.rdx; 55 | let token_information_class = emu.regs.rcx; 56 | let token_information = emu.regs.r8; 57 | let token_information_length = emu.regs.r9; 58 | let return_length = emu.maps.read_qword(emu.regs.rsp); 59 | 60 | log::info!( 61 | "{}** {} kernelbase!GetTokenInformation token_information_class: 0x{:x} {}", 62 | emu.colors.light_red, emu.pos, token_information_class, emu.colors.nc 63 | ); 64 | 65 | emu.regs.rax = 1; 66 | } 67 | -------------------------------------------------------------------------------- /src/emu/winapi64/shell32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | 3 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 4 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 5 | match apiname.as_str() { 6 | "RealShellExecuteA" => RealShellExecuteA(emu), 7 | _ => { 8 | log::info!("calling unimplemented shell32 API 0x{:x} {}", addr, apiname); 9 | return apiname; 10 | } 11 | } 12 | return String::new(); 13 | } 14 | 15 | fn RealShellExecuteA(emu: &mut emu::Emu) { 16 | let handle = emu.regs.rcx; 17 | let operation = emu.regs.rdx; 18 | let file_ptr = emu.regs.r8; 19 | let params_ptr = emu.regs.r9; 20 | let dir = emu 21 | .maps 22 | .read_qword(emu.regs.rsp) 23 | .expect("cannot read parameter"); 24 | let bShowWindow = emu 25 | .maps 26 | .read_qword(emu.regs.rsp + 8) 27 | .expect("cannot read parameter"); 28 | 29 | let file = emu.maps.read_string(file_ptr); 30 | let params = emu.maps.read_string(params_ptr); 31 | 32 | log::info!( 33 | "{}** {} shell32!RealShellExecuteA {} {} {}", 34 | emu.colors.light_red, emu.pos, file, params, emu.colors.nc 35 | ); 36 | 37 | emu.regs.rax = 34; 38 | } 39 | -------------------------------------------------------------------------------- /src/emu/winapi64/shlwapi.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | //use crate::emu::constants; 3 | //use crate::emu::winapi32::helper; 4 | 5 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 6 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 7 | match apiname.as_str() { 8 | "PathIsContentTypeW" => PathIsContentTypeW(emu), 9 | "PathFindSuffixArrayA" => PathFindSuffixArrayA(emu), 10 | 11 | _ => { 12 | log::info!( 13 | "calling unimplemented shlwapi API 0x{:x} {}", 14 | addr, apiname 15 | ); 16 | return apiname; 17 | } 18 | } 19 | 20 | return String::new(); 21 | } 22 | 23 | pub fn PathIsContentTypeW(emu: &mut emu::Emu) { 24 | let path = emu.maps.read_wide_string(emu.regs.rcx); 25 | let content_type = emu.maps.read_wide_string(emu.regs.rdx); 26 | 27 | log::info!( 28 | "{}** {} shlwapi!PathIsContentTypeW path: {} content-type: {} {}", 29 | emu.colors.light_red, emu.pos, path, content_type, emu.colors.nc 30 | ); 31 | 32 | emu.regs.rax = 1; 33 | } 34 | 35 | pub fn PathFindSuffixArrayA(emu: &mut emu::Emu) { 36 | let path = emu.maps.read_string(emu.regs.rcx); 37 | let suffixes = emu.maps.read_string(emu.regs.rdx); 38 | 39 | log::info!( 40 | "{}** {} shlwapi!PathFindSuffixArrayA path: {} suffixes: {} {}", 41 | emu.colors.light_red, emu.pos, path, suffixes, emu.colors.nc 42 | ); 43 | 44 | emu.regs.rax = emu.regs.rdx; 45 | } 46 | -------------------------------------------------------------------------------- /src/emu/winapi64/user32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | 3 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 4 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 5 | match apiname.as_str() { 6 | "MessageBoxA" => MessageBoxA(emu), 7 | "GetDesktopWindow" => GetDesktopWindow(emu), 8 | 9 | _ => { 10 | log::info!("calling unimplemented user32 API 0x{:x} {}", addr, apiname); 11 | return apiname; 12 | } 13 | } 14 | return String::new(); 15 | } 16 | 17 | fn MessageBoxA(emu: &mut emu::Emu) { 18 | let titleptr = emu.regs.rcx; 19 | let msgptr = emu.regs.rdx; 20 | let msg = emu.maps.read_string(msgptr); 21 | let title = emu.maps.read_string(titleptr); 22 | 23 | log::info!( 24 | "{}** {} user32!MessageBoxA {} {} {}", 25 | emu.colors.light_red, emu.pos, title, msg, emu.colors.nc 26 | ); 27 | 28 | emu.regs.rax = 0; 29 | } 30 | 31 | fn GetDesktopWindow(emu: &mut emu::Emu) { 32 | log::info!( 33 | "{}** {} user32!GetDesktopWindow {}", 34 | emu.colors.light_red, emu.pos, emu.colors.nc 35 | ); 36 | //emu.regs.rax = 0x11223344; // current window handle 37 | emu.regs.rax = 0; // no windows handler is more stealthy 38 | } 39 | -------------------------------------------------------------------------------- /src/emu/winapi64/winhttp.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | 3 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 4 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 5 | match apiname.as_str() { 6 | /*"StartServiceCtrlDispatcherA" => StartServiceCtrlDispatcherA(emu), 7 | "StartServiceCtrlDispatcherW" => StartServiceCtrlDispatcherW(emu),*/ 8 | _ => { 9 | log::info!("calling unimplemented winhttp API 0x{:x} {}", addr, apiname); 10 | return apiname; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/emu/winapi64/wininet.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | use crate::emu::constants; 3 | //use crate::emu::endpoint; 4 | use crate::emu::winapi32::helper; 5 | use lazy_static::lazy_static; 6 | use std::sync::Mutex; 7 | 8 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 9 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 10 | match apiname.as_str() { 11 | "InternetOpenA" => InternetOpenA(emu), 12 | "InternetOpenW" => InternetOpenW(emu), 13 | "InternetConnectA" => InternetConnectA(emu), 14 | "InternetConnectW" => InternetConnectW(emu), 15 | "HttpOpenRequestA" => HttpOpenRequestA(emu), 16 | "HttpOpenRequestW" => HttpOpenRequestW(emu), 17 | "InternetSetOptionA" => InternetSetOptionA(emu), 18 | "InternetSetOptionW" => InternetSetOptionW(emu), 19 | "HttpSendRequestA" => HttpSendRequestA(emu), 20 | "HttpSendRequestW" => HttpSendRequestW(emu), 21 | "InternetReadFile" => InternetReadFile(emu), 22 | "InternetReadFileExA" => InternetReadFileExA(emu), 23 | "InternetReadFileExW" => InternetReadFileExW(emu), 24 | "InternetErrorDlg" => InternetErrorDlg(emu), 25 | _ => { 26 | log::info!("calling unimplemented wininet API 0x{:x} {}", addr, apiname); 27 | return apiname; 28 | } 29 | } 30 | 31 | return String::new(); 32 | } 33 | 34 | lazy_static! { 35 | static ref COUNT_RECEIVE: Mutex = Mutex::new(0); 36 | } 37 | 38 | pub fn InternetOpenA(emu: &mut emu::Emu) { 39 | let uagent_ptr = emu.regs.rcx; 40 | let access = emu.regs.rdx; 41 | let proxy_ptr = emu.regs.r8; 42 | let proxybypass_ptr = emu.regs.r9; 43 | let flags = emu 44 | .maps 45 | .read_qword(emu.regs.rsp) 46 | .expect("wininet!InternetOpenA cannot read flags"); 47 | 48 | let mut uagent = "".to_string(); 49 | let mut proxy = "".to_string(); 50 | let mut proxy_bypass = "".to_string(); 51 | 52 | if uagent_ptr != 0 { 53 | uagent = emu.maps.read_string(uagent_ptr); 54 | } 55 | if proxy_ptr != 0 { 56 | proxy = emu.maps.read_string(proxy_ptr); 57 | } 58 | if proxybypass_ptr != 0 { 59 | proxy_bypass = emu.maps.read_string(proxybypass_ptr); 60 | } 61 | 62 | log::info!( 63 | "{}** {} wininet!InternetOpenA uagent: {} proxy: {} {} {}", 64 | emu.colors.light_red, emu.pos, uagent, proxy, proxy_bypass, emu.colors.nc 65 | ); 66 | 67 | /* 68 | if emu.cfg.endpoint { 69 | // endpoint mode 70 | if uagent_ptr != 0 && uagent != "" { 71 | endpoint::http_set_headers("User-Agent", &uagent); 72 | } 73 | }*/ 74 | 75 | let uri = format!("InternetOpenA://{}", uagent); 76 | emu.regs.rax = helper::handler_create(&uri); 77 | } 78 | 79 | pub fn InternetOpenW(emu: &mut emu::Emu) { 80 | let uagent_ptr = emu.regs.rcx; 81 | let access = emu.regs.rdx; 82 | let proxy_ptr = emu.regs.r8; 83 | let proxybypass_ptr = emu.regs.r9; 84 | let flags = emu 85 | .maps 86 | .read_qword(emu.regs.rsp) 87 | .expect("wininet!InternetOpenW cannot read flags"); 88 | 89 | let mut uagent = "".to_string(); 90 | let mut proxy = "".to_string(); 91 | let mut proxy_bypass = "".to_string(); 92 | 93 | if uagent_ptr != 0 { 94 | uagent = emu.maps.read_wide_string(uagent_ptr); 95 | } 96 | if proxy_ptr != 0 { 97 | proxy = emu.maps.read_wide_string(proxy_ptr); 98 | } 99 | if proxybypass_ptr != 0 { 100 | proxy_bypass = emu.maps.read_wide_string(proxybypass_ptr); 101 | } 102 | 103 | log::info!( 104 | "{}** {} wininet!InternetOpenW uagent: {} proxy: {} {} {}", 105 | emu.colors.light_red, emu.pos, uagent, proxy, proxy_bypass, emu.colors.nc 106 | ); 107 | 108 | /* 109 | if emu.cfg.endpoint { 110 | // endpoint mode 111 | if uagent_ptr != 0 && uagent != "" { 112 | endpoint::http_set_headers("User-Agent", &uagent.replace("\x00", "")); 113 | } 114 | }*/ 115 | 116 | emu.regs.rax = helper::handler_create("InternetOpenW://"); // internet handle 117 | } 118 | 119 | pub fn InternetConnectA(emu: &mut emu::Emu) { 120 | let internet_hndl = emu.regs.rcx; 121 | let server_ptr = emu.regs.rdx; 122 | let port = emu.regs.r8; 123 | let login_ptr = emu.regs.r9; 124 | let passw_ptr = emu 125 | .maps 126 | .read_qword(emu.regs.rsp) 127 | .expect("wininet!InternetConnectA cannot read passw_ptr") as u64; 128 | let service = emu 129 | .maps 130 | .read_qword(emu.regs.rsp + 8) 131 | .expect("wininet!InternetConnectA cannot read service"); 132 | let flags = emu 133 | .maps 134 | .read_qword(emu.regs.rsp + 16) 135 | .expect("wininet!InternetConnectA cannot read flags"); 136 | let ctx = emu 137 | .maps 138 | .read_qword(emu.regs.rsp + 24) 139 | .expect("wininet!InternetConnectA cannot read ctx"); 140 | 141 | let mut server = "".to_string(); 142 | let mut login = "".to_string(); 143 | let mut passw = "".to_string(); 144 | 145 | if server_ptr != 0 { 146 | server = emu.maps.read_string(server_ptr); 147 | } 148 | if login_ptr != 0 { 149 | login = emu.maps.read_string(login_ptr); 150 | } 151 | if passw_ptr != 0 { 152 | passw = emu.maps.read_string(passw_ptr); 153 | } 154 | 155 | log::info!( 156 | "{}** {} wininet!InternetConnectA host: {} port: {} login: {} passw: {} {}", 157 | emu.colors.light_red, emu.pos, server, port, login, passw, emu.colors.nc 158 | ); 159 | 160 | if !helper::handler_exist(internet_hndl) { 161 | log::info!("\tinvalid handle."); 162 | } 163 | 164 | /* 165 | if emu.cfg.endpoint { 166 | endpoint::http_set_serverport(&server, port as u16); 167 | }*/ 168 | 169 | let uri = format!("InternetConnectA://{}:{}", server, port); 170 | emu.regs.rax = helper::handler_create(&uri); // connect handle 171 | } 172 | 173 | pub fn InternetConnectW(emu: &mut emu::Emu) { 174 | let internet_hndl = emu.regs.rcx; 175 | let server_ptr = emu.regs.rdx; 176 | let port = emu.regs.r8; 177 | let login_ptr = emu.regs.r9; 178 | let passw_ptr = emu 179 | .maps 180 | .read_qword(emu.regs.rsp) 181 | .expect("wininet!InternetConnectW cannot read passw_ptr") as u64; 182 | let service = emu 183 | .maps 184 | .read_qword(emu.regs.rsp + 8) 185 | .expect("wininet!InternetConnectW cannot read service"); 186 | let flags = emu 187 | .maps 188 | .read_qword(emu.regs.rsp + 16) 189 | .expect("wininet!InternetConnectW cannot read flags"); 190 | let ctx = emu 191 | .maps 192 | .read_qword(emu.regs.rsp + 24) 193 | .expect("wininet!InternetConnectW cannot read ctx"); 194 | 195 | let mut server = "".to_string(); 196 | let mut login = "".to_string(); 197 | let mut passw = "".to_string(); 198 | 199 | if server_ptr != 0 { 200 | server = emu.maps.read_wide_string(server_ptr); 201 | } 202 | if login_ptr != 0 { 203 | login = emu.maps.read_wide_string(login_ptr); 204 | } 205 | if passw_ptr != 0 { 206 | passw = emu.maps.read_wide_string(passw_ptr); 207 | } 208 | 209 | log::info!( 210 | "{}** {} wininet!InternetConnectW host: {} port: {} login: {} passw: {} {}", 211 | emu.colors.light_red, emu.pos, server, port, login, passw, emu.colors.nc 212 | ); 213 | 214 | if !helper::handler_exist(internet_hndl) { 215 | log::info!("\tinvalid handle."); 216 | } 217 | 218 | /* 219 | if emu.cfg.endpoint { 220 | endpoint::http_set_serverport(&server.replace("\x00", ""), port as u16); 221 | }*/ 222 | 223 | let uri = format!("InternetConnectW://{}:{}", server, port); 224 | emu.regs.rax = helper::handler_create(&uri); // connect handle 225 | } 226 | 227 | fn HttpOpenRequestA(emu: &mut emu::Emu) { 228 | let conn_hndl = emu.regs.rcx; 229 | let method_ptr = emu.regs.rdx; 230 | let path_ptr = emu.regs.r8; 231 | let version_ptr = emu.regs.r9; 232 | let referrer_ptr = emu 233 | .maps 234 | .read_qword(emu.regs.rsp) 235 | .expect("wininet!HttpOpenRequestA cannot read referrer_ptr") as u64; 236 | let access_ptr = emu 237 | .maps 238 | .read_qword(emu.regs.rsp + 8) 239 | .expect("wininet!HttpOpenRequestA cannot read access_ptr") as u64; 240 | let flags = emu 241 | .maps 242 | .read_qword(emu.regs.rsp + 16) 243 | .expect("wininet!HttpOpenRequestA cannot read flags") as u64; 244 | let ctx = emu 245 | .maps 246 | .read_qword(emu.regs.rsp + 24) 247 | .expect("wininet!HttpOpenRequestA cannot read ctx"); 248 | 249 | let mut method = "".to_string(); 250 | let mut path = "".to_string(); 251 | let mut version = "".to_string(); 252 | let mut referrer = "".to_string(); 253 | let mut access = "".to_string(); 254 | 255 | if method_ptr != 0 { 256 | method = emu.maps.read_string(method_ptr); 257 | } 258 | if path_ptr != 0 { 259 | path = emu.maps.read_string(path_ptr); 260 | } 261 | if version_ptr != 0 { 262 | version = emu.maps.read_string(version_ptr); 263 | } 264 | if referrer_ptr != 0 { 265 | referrer = emu.maps.read_string(referrer_ptr); 266 | } 267 | if access_ptr != 0 { 268 | access = emu.maps.read_string(access_ptr); 269 | } 270 | 271 | log::info!( 272 | "{}** {} wininet!HttpOpenRequestA method: {} path: {} ver: {} ref: {} access: {} {}", 273 | emu.colors.light_red, emu.pos, method, path, version, referrer, access, emu.colors.nc 274 | ); 275 | 276 | if !helper::handler_exist(conn_hndl) { 277 | log::info!("\tinvalid handle."); 278 | } 279 | 280 | if flags & constants::INTERNET_FLAG_SECURE == 1 { 281 | log::info!("\tssl communication."); 282 | } 283 | 284 | /* 285 | if emu.cfg.endpoint { 286 | endpoint::http_set_path(&path); 287 | if flags & constants::INTERNET_FLAG_SECURE == 1 { 288 | endpoint::http_set_ssl(); 289 | } 290 | 291 | if method_ptr != 0 { 292 | if method == "" { 293 | endpoint::http_set_method("get"); 294 | } else { 295 | endpoint::http_set_method(&method); 296 | } 297 | } else { 298 | endpoint::http_set_method("get"); 299 | } 300 | }*/ 301 | 302 | let uri = format!("HttpOpenRequestA://{}", path); 303 | emu.regs.rax = helper::handler_create(&uri); // request handle 304 | } 305 | 306 | fn HttpOpenRequestW(emu: &mut emu::Emu) { 307 | let conn_hndl = emu.regs.rcx; 308 | let method_ptr = emu.regs.rdx; 309 | let path_ptr = emu.regs.r8; 310 | let version_ptr = emu.regs.r9; 311 | let referrer_ptr = emu 312 | .maps 313 | .read_qword(emu.regs.rsp) 314 | .expect("wininet!HttpOpenRequestW cannot read referrer_ptr") as u64; 315 | let access_ptr = emu 316 | .maps 317 | .read_qword(emu.regs.rsp + 8) 318 | .expect("wininet!HttpOpenRequestW cannot read access_ptr") as u64; 319 | let flags = emu 320 | .maps 321 | .read_qword(emu.regs.rsp + 16) 322 | .expect("wininet!HttpOpenRequestW cannot read flags") as u64; 323 | let ctx = emu 324 | .maps 325 | .read_qword(emu.regs.rsp + 24) 326 | .expect("wininet!HttpOpenRequestW cannot read ctx"); 327 | 328 | let mut method = "".to_string(); 329 | let mut path = "".to_string(); 330 | let mut version = "".to_string(); 331 | let mut referrer = "".to_string(); 332 | let mut access = "".to_string(); 333 | if method_ptr != 0 { 334 | method = emu.maps.read_wide_string(method_ptr); 335 | } 336 | if path_ptr != 0 { 337 | path = emu.maps.read_wide_string(path_ptr); 338 | } 339 | if version_ptr != 0 { 340 | version = emu.maps.read_wide_string(version_ptr); 341 | } 342 | if referrer_ptr != 0 { 343 | referrer = emu.maps.read_wide_string(referrer_ptr); 344 | } 345 | if access_ptr != 0 { 346 | access = emu.maps.read_wide_string(access_ptr); 347 | } 348 | 349 | log::info!( 350 | "{}** {} wininet!HttpOpenRequestW method: {} path: {} ver: {} ref: {} access: {} {}", 351 | emu.colors.light_red, emu.pos, method, path, version, referrer, access, emu.colors.nc 352 | ); 353 | 354 | if !helper::handler_exist(conn_hndl) { 355 | log::info!("\tinvalid handle."); 356 | } 357 | 358 | /* 359 | if emu.cfg.endpoint { 360 | endpoint::http_set_path(&path); 361 | if flags & constants::INTERNET_FLAG_SECURE == 1 { 362 | endpoint::http_set_ssl(); 363 | } 364 | 365 | if method_ptr != 0 { 366 | if method.len() < 3 { 367 | endpoint::http_set_method("get"); 368 | } else { 369 | endpoint::http_set_method(&method.replace("\x00", "")); 370 | } 371 | } else { 372 | endpoint::http_set_method("get"); 373 | } 374 | }*/ 375 | 376 | let uri = format!("HttpOpenRequestW://{}", path); 377 | emu.regs.rax = helper::handler_create(&uri); // request handle 378 | } 379 | 380 | fn InternetSetOptionA(emu: &mut emu::Emu) { 381 | let inet_hndl = emu.regs.rcx; 382 | let option = emu.regs.rdx; 383 | let buffer = emu.regs.r8; 384 | let len = emu.regs.r9; 385 | 386 | let mut buffer_content = "".to_string(); 387 | if buffer != 0 { 388 | buffer_content = emu.maps.read_string_of_bytes(buffer, len as usize); 389 | } 390 | let sbuff = emu.maps.read_string(buffer); 391 | 392 | log::info!( 393 | "{}** {} wininet!InternetSetOptionA option: 0x{:x} buff: {{{}}} {} {}", 394 | emu.colors.light_red, emu.pos, option, buffer_content, sbuff, emu.colors.nc 395 | ); 396 | 397 | if !helper::handler_exist(inet_hndl) { 398 | log::info!("\tinvalid handle."); 399 | } 400 | 401 | emu.regs.rax = 1; // true 402 | } 403 | 404 | fn InternetSetOptionW(emu: &mut emu::Emu) { 405 | let inet_hndl = emu.regs.rcx; 406 | let option = emu.regs.rdx; 407 | let buffer = emu.regs.r8; 408 | let len = emu.regs.r9; 409 | 410 | let mut buffer_content = "".to_string(); 411 | if buffer != 0 { 412 | buffer_content = emu.maps.read_string_of_bytes(buffer, len as usize); 413 | } 414 | let sbuff = emu.maps.read_wide_string(buffer); 415 | 416 | log::info!( 417 | "{}** {} wininet!InternetSetOptionW option: 0x{:x} buff: {{{}}} {} {}", 418 | emu.colors.light_red, emu.pos, option, buffer_content, sbuff, emu.colors.nc 419 | ); 420 | 421 | if !helper::handler_exist(inet_hndl) { 422 | log::info!("\tinvalid handle."); 423 | } 424 | 425 | emu.regs.rax = 1; // true 426 | } 427 | 428 | fn HttpSendRequestA(emu: &mut emu::Emu) { 429 | let req_hndl = emu.regs.rcx; 430 | let hdrs_ptr = emu.regs.rdx; 431 | let hdrs_len = emu.regs.r8; 432 | let opt_ptr = emu.regs.r9; 433 | let opt_len = emu 434 | .maps 435 | .read_qword(emu.regs.rsp) 436 | .expect("wininet!HttpSendRequestA cannot read opt_len"); 437 | 438 | let hdrs = emu.maps.read_string(hdrs_ptr); 439 | let opt = emu.maps.read_string(opt_ptr); 440 | 441 | log::info!( 442 | "{}** {} wininet!HttpSendRequestA hdrs: {} opt: {} {}", 443 | emu.colors.light_red, emu.pos, hdrs, opt, emu.colors.nc 444 | ); 445 | 446 | if !helper::handler_exist(req_hndl) { 447 | log::info!("\tinvalid handle."); 448 | } 449 | 450 | /* 451 | if emu.cfg.endpoint { 452 | endpoint::http_set_headers_str(&hdrs); 453 | endpoint::http_send_request(); 454 | }*/ 455 | 456 | emu.regs.rax = 1; // true 457 | } 458 | 459 | fn HttpSendRequestW(emu: &mut emu::Emu) { 460 | let req_hndl = emu.regs.rcx; 461 | let hdrs_ptr = emu.regs.rdx; 462 | let hdrs_len = emu.regs.r8; 463 | let opt_ptr = emu.regs.r9; 464 | let opt_len = emu 465 | .maps 466 | .read_qword(emu.regs.rsp) 467 | .expect("wininet!HttpSendRequestW cannot read opt_len"); 468 | 469 | let hdrs = emu.maps.read_wide_string(hdrs_ptr); 470 | let opt = emu.maps.read_wide_string(opt_ptr); 471 | 472 | log::info!( 473 | "{}** {} wininet!HttpSendRequestW hdrs: {} opt: {} {}", 474 | emu.colors.light_red, emu.pos, hdrs, opt, emu.colors.nc 475 | ); 476 | 477 | if !helper::handler_exist(req_hndl) { 478 | log::info!("\tinvalid handle."); 479 | } 480 | 481 | /* 482 | if emu.cfg.endpoint { 483 | endpoint::http_set_headers_str(&hdrs.replace("\x00", "")); 484 | endpoint::http_send_request(); 485 | }*/ 486 | 487 | emu.regs.rax = 1; // true 488 | } 489 | 490 | fn InternetErrorDlg(emu: &mut emu::Emu) { 491 | let err = emu.regs.rcx; 492 | 493 | log::info!( 494 | "{}** {} wininet!InternetErrorDlg err: {} {}", 495 | emu.colors.light_red, emu.pos, err, emu.colors.nc 496 | ); 497 | 498 | emu.regs.rax = 0; 499 | } 500 | 501 | fn InternetReadFile(emu: &mut emu::Emu) { 502 | let file_hndl = emu.regs.rcx; 503 | let buff_ptr = emu.regs.rdx; 504 | let bytes_to_read = emu.regs.r8; 505 | let bytes_read_ptr = emu.regs.r9; 506 | 507 | log::info!( 508 | "{}** {} wininet!InternetReadFile sz: {} buff: 0x{:x} {}", 509 | emu.colors.light_red, emu.pos, bytes_to_read, buff_ptr, emu.colors.nc 510 | ); 511 | 512 | if !helper::handler_exist(file_hndl) { 513 | log::info!("\tinvalid handle."); 514 | } 515 | 516 | if emu.cfg.endpoint { 517 | /* 518 | let buff = endpoint::http_read_data(); 519 | emu.maps.write_buffer(buff_ptr, &buff); 520 | emu.maps.write_dword(bytes_read_ptr, buff.len() as u32); 521 | */ 522 | } else { 523 | let mut count = COUNT_RECEIVE.lock().unwrap(); 524 | *count += 1; 525 | 526 | if *count < 3 { 527 | emu.maps.write_spaced_bytes(buff_ptr, "90 90 90 90"); 528 | emu.maps.write_dword(bytes_read_ptr, bytes_to_read as u32); 529 | } else { 530 | emu.maps.write_dword(bytes_read_ptr, 0); 531 | } 532 | } 533 | 534 | emu.regs.rax = 1; // true 535 | } 536 | 537 | fn InternetReadFileExA(emu: &mut emu::Emu) { 538 | let file_hndl = emu.regs.rcx; 539 | let buff_ptr = emu.regs.rdx; 540 | let flags = emu.regs.r8; 541 | let ctx = emu.regs.r9; 542 | 543 | log::info!( 544 | "{}** {} wininet!InternetReadFileExA buff: 0x{:x} {}", 545 | emu.colors.light_red, emu.pos, buff_ptr, emu.colors.nc 546 | ); 547 | 548 | if !helper::handler_exist(file_hndl) { 549 | log::info!("\tinvalid handle."); 550 | } 551 | 552 | emu.regs.rax = 1; // true 553 | } 554 | 555 | fn InternetReadFileExW(emu: &mut emu::Emu) { 556 | let file_hndl = emu.regs.rcx; 557 | let buff_ptr = emu.regs.rdx; 558 | let flags = emu.regs.r8; 559 | let ctx = emu.regs.r9; 560 | 561 | log::info!( 562 | "{}** {} wininet!InternetReadFileExW buff: 0x{:x} {}", 563 | emu.colors.light_red, emu.pos, buff_ptr, emu.colors.nc 564 | ); 565 | 566 | if !helper::handler_exist(file_hndl) { 567 | log::info!("\tinvalid handle."); 568 | } 569 | 570 | emu.regs.rax = 1; // true 571 | } 572 | -------------------------------------------------------------------------------- /src/emu/winapi64/ws2_32.rs: -------------------------------------------------------------------------------- 1 | use crate::emu; 2 | //use crate::emu::endpoint; 3 | use crate::emu::structures::*; 4 | use crate::emu::winapi32::helper; 5 | 6 | use lazy_static::lazy_static; 7 | use std::sync::Mutex; 8 | 9 | pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { 10 | let apiname = emu::winapi64::kernel32::guess_api_name(emu, addr); 11 | match apiname.as_str() { 12 | "WSAStartup" => WsaStartup(emu), 13 | "WSASocketA" => WsaSocketA(emu), 14 | "connect" => connect(emu), 15 | "recv" => recv(emu), 16 | "send" => send(emu), 17 | "socket" => socket(emu), 18 | "WsaHtons" => WsaHtons(emu), 19 | "htons" => htons(emu), 20 | "inet_addr" => inet_addr(emu), 21 | "bind" => bind(emu), 22 | "listen" => listen(emu), 23 | "accept" => accept(emu), 24 | "closesocket" => closesocket(emu), 25 | "setsockopt" => setsockopt(emu), 26 | "getsockopt" => getsockopt(emu), 27 | "WsaAccept" => WsaAccept(emu), 28 | "GetSockName" => GetSockName(emu), 29 | "gethostbyname" => gethostbyname(emu), 30 | /* 31 | "sendto" => sendto(emu), 32 | "recvfrom" => recvfrom(emu), 33 | "WsaRecv" => WsaRecv(emu), 34 | "WsaRecvFrom" => WsaRecvFrom(emu), 35 | "WsaConnect" => WsaConnect(emu), 36 | */ 37 | _ => { 38 | log::info!("calling unimplemented ws2_32 API 0x{:x} {}", addr, apiname); 39 | return apiname; 40 | } 41 | } 42 | 43 | return String::new(); 44 | } 45 | 46 | lazy_static! { 47 | static ref COUNT_SEND: Mutex = Mutex::new(0); 48 | static ref COUNT_RECV: Mutex = Mutex::new(0); 49 | } 50 | 51 | fn WsaStartup(emu: &mut emu::Emu) { 52 | log::info!( 53 | "{}** {} ws2_32!WsaStartup {}", 54 | emu.colors.light_red, emu.pos, emu.colors.nc 55 | ); 56 | 57 | emu.regs.rax = 0; 58 | } 59 | 60 | fn WsaSocketA(emu: &mut emu::Emu) { 61 | log::info!( 62 | "{}** {} ws2_32!WsaSocketA {}", 63 | emu.colors.light_red, emu.pos, emu.colors.nc 64 | ); 65 | 66 | emu.regs.rax = helper::socket_create(); 67 | } 68 | 69 | fn socket(emu: &mut emu::Emu) { 70 | log::info!( 71 | "{}** {} ws2_32!socket {}", 72 | emu.colors.light_red, emu.pos, emu.colors.nc 73 | ); 74 | 75 | emu.regs.rax = helper::socket_create(); 76 | } 77 | 78 | fn WsaHtons(emu: &mut emu::Emu) { 79 | let host_port = emu.regs.rdx; 80 | let out_port = emu.regs.r8; 81 | 82 | log::info!( 83 | "{}** {} ws2_32!WsaHtons {} {}", 84 | emu.colors.light_red, emu.pos, host_port, emu.colors.nc 85 | ); 86 | 87 | //TODO: implement this 88 | emu.regs.rax = 0; 89 | } 90 | 91 | fn htons(emu: &mut emu::Emu) { 92 | let port: u16 = emu.regs.rcx as u16; 93 | 94 | log::info!( 95 | "{}** {} ws2_32!htons port: {} {}", 96 | emu.colors.light_red, emu.pos, port, emu.colors.nc 97 | ); 98 | 99 | emu.regs.rax = port.to_be() as u64; 100 | } 101 | 102 | fn inet_addr(emu: &mut emu::Emu) { 103 | let addr = emu.regs.rcx; 104 | 105 | //TODO: derreferece addr 106 | 107 | log::info!( 108 | "{}** {} ws2_32!inet_addr {}", 109 | emu.colors.light_red, emu.pos, emu.colors.nc 110 | ); 111 | 112 | emu.regs.rax = 0; 113 | } 114 | 115 | fn connect(emu: &mut emu::Emu) { 116 | let sock = emu.regs.rcx; 117 | let sockaddr_ptr = emu.regs.rdx; 118 | //let sockaddr = emu.maps.read_bytes(sockaddr_ptr, 8); 119 | let family: u16 = emu 120 | .maps 121 | .read_word(sockaddr_ptr) 122 | .expect("ws2_32!connect: error reading family"); 123 | let port: u16 = emu 124 | .maps 125 | .read_word(sockaddr_ptr + 2) 126 | .expect("ws2_32!connect: error reading port") 127 | .to_be(); 128 | let ip: u32 = emu 129 | .maps 130 | .read_dword(sockaddr_ptr + 4) 131 | .expect("ws2_32!connect: error reading ip"); 132 | 133 | let sip = format!( 134 | "{}.{}.{}.{}", 135 | ip & 0xff, 136 | (ip & 0xff00) >> 8, 137 | (ip & 0xff0000) >> 16, 138 | (ip & 0xff000000) >> 24 139 | ); 140 | log::info!( 141 | "{}** {} ws2_32!connect family: {} {}:{} {}", 142 | emu.colors.light_red, emu.pos, family, sip, port, emu.colors.nc 143 | ); 144 | 145 | if emu.cfg.endpoint { 146 | /* 147 | if endpoint::sock_connect(sip.as_str(), port) { 148 | log::info!("\tconnected to the endpoint."); 149 | } else { 150 | log::info!("\tcannot connect. dont use -e"); 151 | }*/ 152 | emu.regs.rax = 0; 153 | } else { 154 | // offline mode 155 | 156 | if !helper::socket_exist(sock) { 157 | log::info!("\tinvalid socket."); 158 | emu.regs.rax = 1; 159 | } else { 160 | emu.regs.rax = 0; 161 | } 162 | } 163 | } 164 | 165 | fn recv(emu: &mut emu::Emu) { 166 | let sock = emu.regs.rcx; 167 | let buff = emu.regs.rdx; 168 | let mut len = emu.regs.r8; 169 | let flags = emu.regs.r9; 170 | 171 | log::info!( 172 | "{}** {} ws2_32!recv buff: 0x{:x} sz: {} {}", 173 | emu.colors.light_red, emu.pos, buff, len, emu.colors.nc 174 | ); 175 | 176 | if !helper::socket_exist(sock) { 177 | log::info!("\tinvalid socket."); 178 | emu.regs.rax = 1; 179 | return; 180 | } 181 | 182 | if emu.cfg.endpoint { 183 | /* 184 | let mut rbuff: Vec = vec![0; len as usize]; 185 | let n = endpoint::sock_recv(&mut rbuff); 186 | 187 | emu.maps.write_buffer(buff, &rbuff); 188 | 189 | log::info!("\nreceived {} bytes from the endpoint.", n); 190 | emu.regs.rax = n as u64; 191 | */ 192 | } else { 193 | let mut count_recv = COUNT_RECV.lock().unwrap(); 194 | *count_recv += 1; 195 | if *count_recv > 3 { 196 | len = 0; // finish the recv loop 197 | } 198 | 199 | if helper::socket_exist(sock) { 200 | //emu.maps.write_spaced_bytes(buff, "6c 73 0d 0a".to_string()); // send a ls\r\n 201 | if len == 4 { 202 | emu.maps.write_dword(buff, 0x0100); // probably expect a size 203 | } else { 204 | emu.maps.memset(buff, 0x90, len as usize); 205 | } 206 | 207 | emu.regs.rax = len; 208 | } 209 | } 210 | } 211 | 212 | fn send(emu: &mut emu::Emu) { 213 | let sock = emu.regs.rcx; 214 | let buff = emu.regs.rdx; 215 | let mut len = emu.regs.r8; 216 | let flags = emu.regs.r9; 217 | 218 | let bytes = emu.maps.read_string_of_bytes(buff, len as usize); 219 | 220 | log::info!( 221 | "{}** {} ws2_32!send {{{}}} {}", 222 | emu.colors.light_red, emu.pos, bytes, emu.colors.nc 223 | ); 224 | 225 | if !helper::socket_exist(sock) { 226 | log::info!("\tinvalid socket."); 227 | emu.regs.rax = 0; 228 | return; 229 | } 230 | 231 | if emu.cfg.endpoint { 232 | /* 233 | let buffer = emu.maps.read_buffer(buff, len as usize); 234 | let n = endpoint::sock_send(&buffer); 235 | log::info!("\tsent {} bytes.", n); 236 | emu.regs.rax = n as u64; 237 | */ 238 | } else { 239 | let mut count_send = COUNT_SEND.lock().unwrap(); 240 | *count_send += 1; 241 | if *count_send > 3 { 242 | len = 0; // finish the send loop 243 | } 244 | 245 | emu.regs.rax = len; 246 | } 247 | } 248 | 249 | fn bind(emu: &mut emu::Emu) { 250 | let sock = emu.regs.rcx; 251 | let saddr = emu.regs.rdx; 252 | let len = emu.regs.r8; 253 | 254 | let family: u16 = emu 255 | .maps 256 | .read_word(saddr) 257 | .expect("ws2_32!connect: error reading family"); 258 | let port: u16 = emu 259 | .maps 260 | .read_word(saddr + 2) 261 | .expect("ws2_32!connect: error reading port"); 262 | let ip: u32 = emu 263 | .maps 264 | .read_dword(saddr + 4) 265 | .expect("ws2_32!connect: error reading ip"); 266 | 267 | let sip = format!( 268 | "{}.{}.{}.{}", 269 | ip & 0xff, 270 | (ip & 0xff00) >> 8, 271 | (ip & 0xff0000) >> 16, 272 | (ip & 0xff000000) >> 24 273 | ); 274 | 275 | log::info!( 276 | "{}** {} ws2_32!bind family: {} {}:{} {}", 277 | emu.colors.light_red, 278 | emu.pos, 279 | family, 280 | sip, 281 | port.to_be(), 282 | emu.colors.nc 283 | ); 284 | 285 | if !helper::socket_exist(sock) { 286 | log::info!("\tbad socket."); 287 | emu.regs.rax = 1; 288 | } else { 289 | emu.regs.rax = 0; 290 | } 291 | } 292 | 293 | fn listen(emu: &mut emu::Emu) { 294 | let sock = emu.regs.rcx; 295 | let connections = emu.regs.rdx; 296 | 297 | log::info!( 298 | "{}** {} ws2_32!listen connections: {} {}", 299 | emu.colors.light_red, emu.pos, connections, emu.colors.nc 300 | ); 301 | 302 | if !helper::socket_exist(sock) { 303 | log::info!("\tinvalid socket."); 304 | emu.regs.rax = 1; 305 | } else { 306 | emu.regs.rax = 0; 307 | } 308 | } 309 | 310 | fn accept(emu: &mut emu::Emu) { 311 | let sock = emu.regs.rcx; 312 | let saddr = emu.regs.rdx; 313 | let len = emu.regs.r8; 314 | let flags = emu.regs.r9; 315 | 316 | let bytes = emu.maps.read_string_of_bytes(saddr, len as usize); 317 | 318 | log::info!( 319 | "{}** {} ws2_32!accept connections: {} {}", 320 | emu.colors.light_red, emu.pos, bytes, emu.colors.nc 321 | ); 322 | 323 | if !helper::socket_exist(sock) { 324 | log::info!("\tinvalid socket."); 325 | emu.regs.rax = 1; 326 | } else { 327 | emu.regs.rax = 0; 328 | } 329 | } 330 | 331 | fn closesocket(emu: &mut emu::Emu) { 332 | let sock = emu.regs.rcx; 333 | 334 | log::info!( 335 | "{}** {} ws2_32!closesocket {}", 336 | emu.colors.light_red, emu.pos, emu.colors.nc 337 | ); 338 | 339 | helper::socket_close(sock); 340 | 341 | /* 342 | if emu.cfg.endpoint { 343 | endpoint::sock_close(); 344 | }*/ 345 | 346 | emu.regs.rax = 0; 347 | } 348 | 349 | fn setsockopt(emu: &mut emu::Emu) { 350 | let sock = emu.regs.rcx; 351 | let level = emu.regs.rdx; 352 | let optname = emu.regs.r8; 353 | let optval = emu.regs.r9; 354 | let optlen = emu 355 | .maps 356 | .read_qword(emu.regs.get_esp()) 357 | .expect("ws2_32!setsockopt: error reading optlen"); 358 | 359 | let val = match emu.maps.read_dword(optval) { 360 | Some(v) => v, 361 | None => 0, 362 | }; 363 | 364 | log::info!( 365 | "{}** {} ws2_32!setsockopt lvl: {} opt: {} val: {} {}", 366 | emu.colors.light_red, emu.pos, level, optname, val, emu.colors.nc 367 | ); 368 | 369 | if !helper::socket_exist(sock) { 370 | log::info!("\tinvalid socket."); 371 | emu.regs.rax = 1; 372 | } else { 373 | emu.regs.rax = 0; 374 | } 375 | } 376 | 377 | fn getsockopt(emu: &mut emu::Emu) { 378 | let sock = emu.regs.rcx; 379 | let level = emu.regs.rdx; 380 | let optname = emu.regs.r8; 381 | let optval = emu.regs.r9; 382 | let optlen = emu 383 | .maps 384 | .read_qword(emu.regs.get_esp()) 385 | .expect("ws2_32!getsockopt: error reading optlen") as u64; 386 | 387 | emu.maps.write_dword(optval, 1); 388 | 389 | log::info!( 390 | "{}** {} ws2_32!getsockopt lvl: {} opt: {} {}", 391 | emu.colors.light_red, emu.pos, level, optname, emu.colors.nc 392 | ); 393 | 394 | if !helper::socket_exist(sock) { 395 | log::info!("\tinvalid socket."); 396 | emu.regs.rax = 1; 397 | } else { 398 | emu.regs.rax = 0; 399 | } 400 | } 401 | 402 | fn WsaAccept(emu: &mut emu::Emu) { 403 | let sock = emu.regs.rcx; 404 | let saddr = emu.regs.rdx; 405 | let len = emu.regs.r8; 406 | let cond = emu.regs.r9; 407 | let callback = emu 408 | .maps 409 | .read_qword(emu.regs.get_esp()) 410 | .expect("ws2_32!WsaAccept: error reading callback") as u64; 411 | 412 | let bytes = emu.maps.read_string_of_bytes(saddr, len as usize); 413 | 414 | log::info!( 415 | "{}** {} ws2_32!WsaAccept connections: {} callback: {} {}", 416 | emu.colors.light_red, emu.pos, bytes, callback, emu.colors.nc 417 | ); 418 | 419 | if !helper::socket_exist(sock) { 420 | log::info!("\tinvalid socket."); 421 | emu.regs.rax = 1; 422 | } else { 423 | emu.regs.rax = 0; 424 | } 425 | } 426 | 427 | fn GetSockName(emu: &mut emu::Emu) { 428 | let sock = emu.regs.rcx; 429 | let sockaddr_ptr = emu.regs.rdx; 430 | let namelen_ptr = emu.regs.r8; 431 | 432 | emu.maps.write_dword(sockaddr_ptr, 0); 433 | emu.maps.write_dword(namelen_ptr, 4); 434 | 435 | log::info!( 436 | "{}** {} ws2_32!GetSockName sock: {} {}", 437 | emu.colors.light_red, emu.pos, sock, emu.colors.nc 438 | ); 439 | 440 | emu.regs.rax = 0; 441 | } 442 | 443 | fn gethostbyname(emu: &mut emu::Emu) { 444 | let domain_name_ptr = emu.regs.rcx; 445 | let domain_name = emu.maps.read_string(domain_name_ptr); 446 | 447 | log::info!( 448 | "{}** {} ws2_32!gethostbyname `{}` {}", 449 | emu.colors.light_red, emu.pos, domain_name, emu.colors.nc 450 | ); 451 | 452 | let addr = emu.maps.alloc(1024).expect("low memory"); 453 | let str_addr = addr + 1024 - 100; 454 | let mem = emu.maps.create_map("hostent", addr, 1024).expect("cannot create hostent map"); 455 | mem.write_dword(addr, 0x04030201); 456 | mem.write_qword(addr + 8, addr); 457 | mem.write_qword(addr + 16, 0); 458 | mem.write_string(str_addr, &domain_name); 459 | 460 | let mut hostent = Hostent::new(); 461 | hostent.hname = str_addr; 462 | hostent.alias_list = 0; 463 | hostent.length = 4; 464 | hostent.addr_list = addr + 8; 465 | hostent.save(addr + 30, &mut emu.maps); 466 | 467 | emu.regs.rax = addr + 30; 468 | } 469 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod emu; 3 | 4 | use config::Config; 5 | use emu::Emu; 6 | 7 | pub fn emu64() -> Emu { 8 | let mut emu = Emu::new(); 9 | let mut cfg = Config::new(); 10 | cfg.is_64bits = true; 11 | emu.set_config(cfg); 12 | emu.disable_ctrlc(); 13 | 14 | emu 15 | } 16 | 17 | pub fn emu32() -> Emu { 18 | let mut emu = Emu::new(); 19 | let mut cfg = Config::new(); 20 | cfg.is_64bits = false; 21 | emu.set_config(cfg); 22 | emu.disable_ctrlc(); 23 | 24 | emu 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | //use super::*; 30 | 31 | #[test] 32 | fn test() { 33 | /* 34 | let mut emu = emu64(); 35 | emu.set_maps_folder("../scemu/maps64/"); 36 | emu.cfg.test_mode = false; 37 | emu.init(); 38 | emu.load_code("../scemu/shellcodes64/"); 39 | emu.cfg.nocolors = true; 40 | emu.set_verbose(0); 41 | emu.cfg.trace_regs = false; 42 | emu.spawn_console_at(2586); 43 | emu.run(0);*/ 44 | 45 | assert!(1 == 1); 46 | 47 | // cannot do tests, maps folder cannot be predicted on test time. 48 | 49 | /* 50 | use crate::emu32; 51 | 52 | let mut emu = emu32(); 53 | emu.set_maps_folder("/tmp/maps32/"); 54 | emu.init(); 55 | emu.load_code("/tmp/maps32/test"); 56 | emu.run(0x3c00a4); 57 | assert!(emu.regs.get_eax() == 0x75e9395c); 58 | 59 | emu = emu64(); 60 | emu.set_maps_folder("/tmp/maps64/"); 61 | emu.init(); 62 | emu.load_code("/tmp/maps64/test"); 63 | emu.run(0x3c002b); 64 | assert!(emu.regs.rax == 0x29); 65 | */ 66 | } 67 | } 68 | --------------------------------------------------------------------------------