From 64124786688ebaace1434fe5424932f4c77264fc Mon Sep 17 00:00:00 2001 From: rootacite <1498045907@qq.com> Date: Wed, 29 Oct 2025 15:13:14 +0800 Subject: [PATCH] [feat] inline hook relocate --- 01/project-hbj-hook/Cargo.lock | 75 ---------------------------- 01/project-hbj-hook/Cargo.toml | 2 - 01/project-hbj-hook/src/asm.rs | 31 ++++++++++-- 01/project-hbj-hook/src/hooks.rs | 16 +++--- 01/project-hbj-hook/src/processes.rs | 44 ++++++++++------ 5 files changed, 65 insertions(+), 103 deletions(-) diff --git a/01/project-hbj-hook/Cargo.lock b/01/project-hbj-hook/Cargo.lock index e60fa6e..24c7e98 100644 --- a/01/project-hbj-hook/Cargo.lock +++ b/01/project-hbj-hook/Cargo.lock @@ -20,36 +20,6 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" -[[package]] -name = "capstone" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a" -dependencies = [ - "capstone-sys", - "libc", -] - -[[package]] -name = "capstone-sys" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "cc" -version = "1.2.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" -dependencies = [ - "find-msvc-tools", - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -62,43 +32,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "ctor" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c9b8bdf64ee849747c1b12eb861d21aa47fa161564f48332f1afe2373bf899" -dependencies = [ - "ctor-proc-macro", - "dtor", -] - -[[package]] -name = "ctor-proc-macro" -version = "0.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" - -[[package]] -name = "dtor" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934" -dependencies = [ - "dtor-proc-macro", -] - -[[package]] -name = "dtor-proc-macro" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" - -[[package]] -name = "find-msvc-tools" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" - [[package]] name = "goblin" version = "0.10.3" @@ -221,8 +154,6 @@ name = "project-hbj-hook" version = "0.1.0" dependencies = [ "anyhow", - "capstone", - "ctor", "goblin", "iced-x86", "libc", @@ -260,12 +191,6 @@ dependencies = [ "syn", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "static_assertions" version = "1.1.0" diff --git a/01/project-hbj-hook/Cargo.toml b/01/project-hbj-hook/Cargo.toml index cb925f7..55899d7 100644 --- a/01/project-hbj-hook/Cargo.toml +++ b/01/project-hbj-hook/Cargo.toml @@ -7,9 +7,7 @@ edition = "2024" iced-x86 = { version = "1.21.0", features = ["code_asm"] } libc = "0.2.177" nix = { version = "0.30.1", features = ["ptrace", "uio", "signal"] } -ctor = "0.6.0" goblin = "0.10.3" memmap2 = "0.9.9" -capstone = "0.13.0" anyhow = "1.0.100" ouroboros = "0.18.5" diff --git a/01/project-hbj-hook/src/asm.rs b/01/project-hbj-hook/src/asm.rs index be5f766..f69d70a 100644 --- a/01/project-hbj-hook/src/asm.rs +++ b/01/project-hbj-hook/src/asm.rs @@ -1,13 +1,38 @@ // asm.rs -use iced_x86::{code_asm::*}; +use std::error::Error; +use iced_x86::{code_asm::*, Formatter, Instruction, NasmFormatter}; -pub fn assemble(addr: u64, op: F) -> Result, Box> +pub fn assemble(addr: u64, op: F) -> Result, Box> where - F: Fn(&mut CodeAssembler) -> Result<(), Box>, + F: Fn(&mut CodeAssembler) -> Result<(), Box>, { let mut asm = CodeAssembler::new(64)?; _ = op(&mut asm); Ok(asm.assemble(addr)?) +} + +pub trait InstructionFormat { + fn fmt_line(&self, formatter: &mut dyn Formatter) -> Result>; + fn fmt_line_default(&self) -> Result>; +} + +impl InstructionFormat for Instruction { + fn fmt_line(&self, formatter: &mut dyn Formatter) -> Result> { + let mut asm_str = String::new(); + formatter.format(self, &mut asm_str); + + Ok(format!( + "{:#016x}[{:02}] {}", + self.ip(), + self.len(), + asm_str + )) + } + + fn fmt_line_default(&self) -> Result> { + let mut fmt = NasmFormatter::new(); + self.fmt_line(&mut fmt) + } } \ No newline at end of file diff --git a/01/project-hbj-hook/src/hooks.rs b/01/project-hbj-hook/src/hooks.rs index 8b9c310..be40841 100644 --- a/01/project-hbj-hook/src/hooks.rs +++ b/01/project-hbj-hook/src/hooks.rs @@ -7,7 +7,7 @@ use crate::map::MemoryMap; use crate::processes::Process; use anyhow::Context; -use crate::asm::assemble; +use crate::asm::{assemble, InstructionFormat}; const GREEN: &str = "\x1b[32m"; const YELLOW: &str = "\x1b[33m"; @@ -99,9 +99,9 @@ where let mut sum_inst_size = 0u32; for i in inst.iter() { - println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.to_string()); + println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?); if (sum_inst_size as usize) < jmp_inst.len() { - sum_inst_size += i.bytes().len() as u32; + sum_inst_size += i.len() as u32; } else { break; } @@ -117,8 +117,8 @@ where // Moving instructions to other locations for execution is !NOT! always safe, // but for library functions, this usually works, - // because the first few instructions are usually endbr64, push ebp or something like that. - let mut gateway = proc.read_memory_vm(remote_addr as usize, sum_inst_size as usize)?; + // because the first few instructions are usually endbr64, push rbp or something like that. + let mut gateway = proc.instruction_relocate(remote_addr, sum_inst_size as u64, gateway_addr)?; println!("{GREEN}[inline hook]{RESET} instruction boundary located at {:#016x}", boundary); @@ -134,7 +134,7 @@ where proc.disassemble(gateway_addr, gateway_sz as u64, |inst| { for i in inst.iter() { - println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.to_string()); + println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?); } Ok(()) })?; @@ -146,14 +146,14 @@ where proc.disassemble(remote_addr, gap_sz as u64, |inst| { for i in inst.iter() { - println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.to_string()); + println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?); } Ok(()) })?; proc.disassemble(remote_addr + gap_sz as u64, 32, |inst| { for i in inst.iter() { - println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.to_string()); + println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?); break; } Ok(()) diff --git a/01/project-hbj-hook/src/processes.rs b/01/project-hbj-hook/src/processes.rs index 8594ea9..bc7df19 100644 --- a/01/project-hbj-hook/src/processes.rs +++ b/01/project-hbj-hook/src/processes.rs @@ -10,10 +10,10 @@ use nix::unistd::Pid; use std::error::Error; use std::io::{IoSliceMut, IoSlice}; -use capstone::{arch, Capstone, Instructions}; -use capstone::arch::{BuildsCapstone, BuildsCapstoneSyntax}; use goblin::elf64::{header, section_header}; use iced_x86::code_asm::{r10, r8, r9, rax, rdi, rdx, rsi}; +use iced_x86::{BlockEncoder, BlockEncoderOptions, Decoder, DecoderOptions, Instruction, InstructionBlock}; + use nix::sys::ptrace; use libc::{user_regs_struct}; use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; @@ -340,23 +340,37 @@ impl Process Ok(r.rax as u64) } - pub fn disassemble(&self, addr: u64, size: u64, callback: F) - -> Result> - where F: Fn(&Instructions) -> Result> + pub fn disassemble( + &self, + addr: u64, + size: u64, + callback: F, + ) -> Result> + where + F: Fn(&[Instruction]) -> Result>, { - let instruction = self.read_memory_vm(addr as usize, size as usize)?; + let code_bytes = self.read_memory_vm(addr as usize, size as usize)?; + let decoder = Decoder::with_ip(64, &code_bytes, addr, DecoderOptions::NONE); + let instructions: Vec = decoder.into_iter().collect(); + let result = callback(&instructions)?; + Ok(result) + } - let cs = Capstone::new() - .x86() - .mode(arch::x86::ArchMode::Mode64) - .syntax(arch::x86::ArchSyntax::Att) - .detail(true) - .build()?; - let inst = cs.disasm_all(&instruction, addr)?; + pub fn instruction_relocate(&self, addr: u64, size: u64, new_addr: u64) + -> Result, Box> + { + let origin = self.read_memory_vm(addr as usize, size as usize)?; - let r = callback(&inst)?; + let decoder = Decoder::with_ip(64, &origin, addr, DecoderOptions::NONE); + let instructions: Vec<_> = decoder.into_iter().collect(); - Ok(r) + let block = InstructionBlock::new(&instructions, new_addr); + let options = BlockEncoderOptions::RETURN_RELOC_INFOS; + + let result = BlockEncoder::encode(64, block, options) + .map_err(|e| format!("BlockEncoder failed: {}", e))?; + + Ok(result.code_buffer.clone()) } }