[feat] inline hook relocate
This commit is contained in:
75
01/project-hbj-hook/Cargo.lock
generated
75
01/project-hbj-hook/Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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<F>(addr: u64, op: F) -> Result<Vec<u8>, Box<dyn std::error::Error>>
|
||||
pub fn assemble<F>(addr: u64, op: F) -> Result<Vec<u8>, Box<dyn Error>>
|
||||
where
|
||||
F: Fn(&mut CodeAssembler) -> Result<(), Box<dyn std::error::Error>>,
|
||||
F: Fn(&mut CodeAssembler) -> Result<(), Box<dyn Error>>,
|
||||
{
|
||||
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<String, Box<dyn Error>>;
|
||||
fn fmt_line_default(&self) -> Result<String, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl InstructionFormat for Instruction {
|
||||
fn fmt_line(&self, formatter: &mut dyn Formatter) -> Result<String, Box<dyn Error>> {
|
||||
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<String, Box<dyn Error>> {
|
||||
let mut fmt = NasmFormatter::new();
|
||||
self.fmt_line(&mut fmt)
|
||||
}
|
||||
}
|
||||
@@ -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(())
|
||||
|
||||
@@ -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<F, T>(&self, addr: u64, size: u64, callback: F)
|
||||
-> Result<T, Box<dyn Error>>
|
||||
where F: Fn(&Instructions) -> Result<T, Box<dyn Error>>
|
||||
pub fn disassemble<F, T>(
|
||||
&self,
|
||||
addr: u64,
|
||||
size: u64,
|
||||
callback: F,
|
||||
) -> Result<T, Box<dyn Error>>
|
||||
where
|
||||
F: Fn(&[Instruction]) -> Result<T, Box<dyn Error>>,
|
||||
{
|
||||
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<Instruction> = 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<Vec<u8>, Box<dyn Error>>
|
||||
{
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user