Add ability to spawn or attach by process name
Signed-off-by: Dimitris Zervas <dzervas@dzervas.gr>
This commit is contained in:
parent
b6a48d5155
commit
ff5a7f152f
85
build.rs
85
build.rs
@ -16,8 +16,8 @@ pub struct Config {
|
||||
pub dll_proxy: Option<String>,
|
||||
pub frida_code: Option<String>,
|
||||
pub frida_code_file: Option<String>,
|
||||
pub target_exec: Option<String>,
|
||||
pub target_process: Option<String>,
|
||||
pub target_spawn: Option<String>,
|
||||
|
||||
pub hooks: Vec<Hook>,
|
||||
}
|
||||
@ -34,8 +34,8 @@ impl Default for Config {
|
||||
dll_proxy : env::var("DLL_PROXY").ok(),
|
||||
frida_code : env::var("FRIDA_CODE").ok(),
|
||||
frida_code_file: env::var("FRIDA_CODE_FILE").ok(),
|
||||
target_exec : env::var("TARGET_SPAWN").ok(),
|
||||
target_process : env::var("TARGET_PROCESS").ok(),
|
||||
target_spawn : env::var("TARGET_SPAWN").ok(),
|
||||
|
||||
hooks: Vec::new(),
|
||||
}
|
||||
@ -58,6 +58,18 @@ impl Config {
|
||||
|
||||
code.replace("\n", "\\n")
|
||||
}
|
||||
|
||||
pub fn populate_env(&self) {
|
||||
if let Some(target_process) = &self.target_process {
|
||||
println!("cargo:rustc-env=TARGET_PROCESS={target_process}");
|
||||
}
|
||||
|
||||
if let Some(target_spawn) = &self.target_spawn {
|
||||
println!("cargo:rustc-env=TARGET_SPAWN={target_spawn}");
|
||||
}
|
||||
|
||||
println!(r#"cargo:rustc-env=FRIDA_CODE={}"#, self.get_frida_code());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -70,17 +82,13 @@ fn main() {
|
||||
Config::default()
|
||||
};
|
||||
|
||||
println!(r#"cargo:rustc-env=FRIDA_CODE={}"#, config.get_frida_code());
|
||||
config.populate_env();
|
||||
|
||||
let Some(lib_path) = config.dll_proxy else {
|
||||
println!("cargo:warning=No dll_proxy set, the resulting library has to be manually injected or compiled into the target binary/process");
|
||||
return;
|
||||
};
|
||||
|
||||
if build_target::target_os() != Ok(build_target::Os::Windows) {
|
||||
panic!("Dll proxying mode is only supported on Windows.");
|
||||
}
|
||||
|
||||
dll_proxy_linker_flags(&lib_path, config.hooks);
|
||||
}
|
||||
|
||||
@ -95,16 +103,65 @@ fn dll_proxy_linker_flags(lib_path: &str, _hooks: Vec<Hook>) {
|
||||
let lib_bytes = std::fs::read(path).expect(format!("Failed to open given library file {lib_filename}").as_str());
|
||||
let object = Object::parse(&lib_bytes).expect(format!("Failed to parse given libary file {lib_filename}").as_str());
|
||||
|
||||
let Object::PE(pe) = object else {
|
||||
panic!("Only PE (.dll) files are supported in this mode.");
|
||||
let (exports, lib_name): (Vec<&str>, String) = match object {
|
||||
Object::PE(o) => {
|
||||
(o.exports
|
||||
.iter()
|
||||
.map(|e| e.name.unwrap())
|
||||
.collect(),
|
||||
o.name.expect("Couldn't read the name of the DLL. Is it a .NET DLL? It's not supported").replace(".dll", ""))
|
||||
}
|
||||
Object::Elf(o) => {
|
||||
(o.dynsyms
|
||||
.iter()
|
||||
.filter(|e| e.is_function() && !e.is_import())
|
||||
.map(|e| o.dynstrtab.get_at(e.st_name).unwrap())
|
||||
.collect(),
|
||||
// o.soname.expect("Couldn't read the name of the SO.").replace(".so", ""))
|
||||
lib_filename.replace(".so", ""))
|
||||
},
|
||||
// Object::Mach(goblin::mach::Mach::Binary(o)) => {
|
||||
// (o.dynsyms
|
||||
// .iter()
|
||||
// .filter(|e| e.is_function() && !e.is_import())
|
||||
// .map(|e| o.dynstrtab.get_at(e.st_name).unwrap())
|
||||
// .collect(),
|
||||
// o.name.expect("Couldn't read the name of the DLL. Is it a .NET DLL? It's not supported").replace(".dll", ""))
|
||||
// },
|
||||
_ => {
|
||||
println!("Only PE (.dll) and ELF (.so) files are supported in their respective target platforms.");
|
||||
std::process::exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
let exports: Vec<&str> = pe.exports.iter().map(|e| e.name.unwrap()).collect();
|
||||
let lib_name = pe.name.expect("Couldn't read the name of the DLL. Is it a .NET DLL? It's not supported").replace(".dll", "");
|
||||
if build_target::target_os() == Ok(build_target::Os::Windows) {
|
||||
for e in exports.iter() {
|
||||
println!("cargo:warning=Exported function: {e} => {lib_name}-orig.{e}");
|
||||
println!("cargo:rustc-link-arg=/export:{e}={lib_name}-orig.{e}");
|
||||
}
|
||||
// } else {
|
||||
// let link_lib_name = if lib_name.starts_with("lib") {
|
||||
// lib_name.replacen("lib", "", 1)
|
||||
// } else {
|
||||
// lib_name.clone()
|
||||
// };
|
||||
|
||||
for e in exports.iter() {
|
||||
println!("cargo:warning=Exported function: {e} => {lib_name}-orig.{e}");
|
||||
println!("cargo:rustc-link-arg=/export:{e}={lib_name}-orig.{e}");
|
||||
// let lib_dir = path.parent().unwrap().to_str().unwrap();
|
||||
|
||||
// let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
// std::fs::copy("test.x", out.join("test.x")).unwrap();
|
||||
// println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// println!("cargo:rustc-link-lib={link_lib_name}");
|
||||
// println!("cargo:rustc-link-search={lib_dir}");
|
||||
// println!("cargo:rustc-link-arg=-l{link_lib_name}");
|
||||
// println!("cargo:rustc-link-arg=-Wl,--no-as-needed");
|
||||
// println!("cargo:rustc-link-arg=-Wl,--just-symbols={lib_path}");
|
||||
|
||||
// for e in exports.iter() {
|
||||
// println!("cargo:warning=Re-exporting function: {e} => {lib_name}-orig.{e}");
|
||||
// println!("cargo:rustc-link-arg=-Wl,--wrap={e}");
|
||||
// }
|
||||
}
|
||||
|
||||
println!("cargo:warning=Expected library name: {lib_name}-orig.dll");
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![cfg(feature = "frida")]
|
||||
|
||||
use frida::{DeviceManager, DeviceType, Frida, ScriptHandler, ScriptOption, ScriptRuntime};
|
||||
use frida::{DeviceManager, DeviceType, Frida, ScriptHandler, ScriptOption, ScriptRuntime, SpawnOptions};
|
||||
use lazy_static::lazy_static;
|
||||
use serde::Deserialize;
|
||||
|
||||
@ -8,31 +8,52 @@ lazy_static! {
|
||||
pub static ref FRIDA: Frida = unsafe { Frida::obtain() };
|
||||
}
|
||||
|
||||
pub fn attach_pid(frida_code: &str, pid: u32) {
|
||||
println!("[+] Injecting into PID: {}", pid);
|
||||
#[derive(Debug)]
|
||||
pub enum AttachMode {
|
||||
Pid(u32),
|
||||
Name(String),
|
||||
Spawn(String),
|
||||
}
|
||||
|
||||
pub fn attach_with(frida_code: &str, mode: AttachMode) {
|
||||
println!("[+] Injecting into: {mode:?}");
|
||||
|
||||
let device_manager = DeviceManager::obtain(&FRIDA);
|
||||
println!("[*] Device Manager obtained");
|
||||
|
||||
if let Ok(device) = device_manager.get_device_by_type(DeviceType::Local) {
|
||||
if let Ok(mut device) = device_manager.get_device_by_type(DeviceType::Local) {
|
||||
println!("[*] First device: {}", device.get_name());
|
||||
|
||||
let pid = match mode {
|
||||
AttachMode::Pid(pid) => pid,
|
||||
AttachMode::Name(ref name) => {
|
||||
device.enumerate_processes().iter()
|
||||
.find(|p| p.get_name() == name)
|
||||
.expect("Process not found")
|
||||
.get_pid()
|
||||
},
|
||||
AttachMode::Spawn(ref name) => device.spawn(name, &SpawnOptions::new()).unwrap(),
|
||||
};
|
||||
|
||||
let session = device.attach(pid).unwrap();
|
||||
|
||||
if !session.is_detached() {
|
||||
println!("[*] Attached");
|
||||
println!("[*] Attached");
|
||||
|
||||
let mut script_option = ScriptOption::new()
|
||||
.set_runtime(ScriptRuntime::QJS);
|
||||
println!("[*] Script {}", frida_code);
|
||||
let script = session
|
||||
.create_script(frida_code, &mut script_option)
|
||||
.unwrap();
|
||||
let mut script_option = ScriptOption::new()
|
||||
.set_runtime(ScriptRuntime::QJS);
|
||||
println!("[*] Script {}", frida_code);
|
||||
let script = session
|
||||
.create_script(frida_code, &mut script_option)
|
||||
.unwrap();
|
||||
|
||||
script.handle_message(&mut Handler).unwrap();
|
||||
script.handle_message(&mut Handler).unwrap();
|
||||
|
||||
script.load().unwrap();
|
||||
println!("[*] Script loaded");
|
||||
script.load().unwrap();
|
||||
println!("[*] Script loaded");
|
||||
|
||||
if let AttachMode::Spawn(_) = mode {
|
||||
device.resume(pid).unwrap();
|
||||
println!("[*] Resuming spawned process")
|
||||
}
|
||||
} else {
|
||||
eprintln!("[!] No device found!");
|
||||
@ -111,7 +132,7 @@ mod tests {
|
||||
}, "uint8", []));
|
||||
"#;
|
||||
|
||||
attach_pid(frida_script, 0);
|
||||
attach_with(frida_script, AttachMode::Pid(0));
|
||||
assert_eq!(20, unsafe { mylib_foo() });
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
compile_error!("No injection method is selected - please enable either dotnet (windows-only) and/or frida feature");
|
||||
|
||||
#[cfg(feature = "frida")]
|
||||
use crate::frida_handler::attach_pid as frida_attach_pid;
|
||||
use crate::frida_handler::attach_with as frida_attach_with;
|
||||
use crate::frida_handler::AttachMode;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn attach(pid: u32) {
|
||||
@ -11,9 +12,26 @@ pub extern "C" fn attach(pid: u32) {
|
||||
{
|
||||
let frida_code = env!("FRIDA_CODE").replace("\\n", "\n");
|
||||
#[cfg(windows)]
|
||||
std::thread::spawn(move || frida_attach_pid(&frida_code, pid));
|
||||
std::thread::spawn(move || frida_attach_pid(&frida_code, AttachMode::Pid(pid)));
|
||||
#[cfg(not(windows))]
|
||||
frida_attach_pid(&frida_code, pid);
|
||||
frida_attach_with(&frida_code, AttachMode::Pid(pid));
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn attach_name(name: *const u8, len: usize) {
|
||||
let name_str = unsafe {
|
||||
let buf = std::slice::from_raw_parts(name, len);
|
||||
std::str::from_utf8(buf).expect("Invalid UTF-8 in process name")
|
||||
};
|
||||
|
||||
#[cfg(feature = "frida")]
|
||||
{
|
||||
let frida_code = env!("FRIDA_CODE").replace("\\n", "\n");
|
||||
#[cfg(windows)]
|
||||
std::thread::spawn(move || frida_attach_with(&frida_code, AttachMode::Name(name_str.to_string())));
|
||||
#[cfg(not(windows))]
|
||||
frida_attach_with(&frida_code, AttachMode::Name(name_str.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,3 +40,22 @@ pub extern "C" fn attach_self() {
|
||||
println!("[*] Attaching to self");
|
||||
attach(0);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn spawn(name: *const u8, len: usize) {
|
||||
let name_str = unsafe {
|
||||
let buf = std::slice::from_raw_parts(name, len);
|
||||
std::str::from_utf8(buf).expect("Invalid UTF-8 in spawn name")
|
||||
};
|
||||
|
||||
println!("[*] Spawning: {name_str}");
|
||||
|
||||
#[cfg(feature = "frida")]
|
||||
{
|
||||
let frida_code = env!("FRIDA_CODE").replace("\\n", "\n");
|
||||
#[cfg(windows)]
|
||||
std::thread::spawn(move || frida_attach_with(&frida_code, AttachMode::Spawn(name_str.to_string())));
|
||||
#[cfg(not(windows))]
|
||||
frida_attach_with(&frida_code, AttachMode::Spawn(name_str.to_string()));
|
||||
}
|
||||
}
|
||||
|
19
src/lib.rs
19
src/lib.rs
@ -56,6 +56,8 @@ Interceptor.replace(foo, new NativeCallback(function () {
|
||||
.arg("tests/mybin/Cargo.toml")
|
||||
.arg("--target-dir")
|
||||
.arg("target/test_frida_on_load")
|
||||
// We're compiling in the same target dir so that frida_deepfreeze_rs is found
|
||||
// We'd have to copy it to the target dir otherwise
|
||||
.env("RUSTFLAGS", "-C link-arg=-Wl,--no-as-needed -C link-arg=-lfrida_deepfreeze_rs")
|
||||
.status()
|
||||
.unwrap();
|
||||
@ -77,18 +79,18 @@ Interceptor.replace(foo, new NativeCallback(function () {
|
||||
.arg("--manifest-path")
|
||||
.arg("tests/mylib/Cargo.toml")
|
||||
.arg("--target-dir")
|
||||
.arg("target/test_frida_dll_proxy")
|
||||
.arg("target/test_frida_dll_proxy/mylib")
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(mylib_status.success(), "Failed to build mylib");
|
||||
|
||||
// fs::copy(format!("target/test_frida_dll_proxy/mylib/debug/{}", get_lib_name("mylib")), format!("target/test_frida_dll_proxy/lib/debug/deps/{}", get_lib_name("mylib-orig"))).expect("Failed to rename original DLL");
|
||||
let lib_status = Command::new("cargo")
|
||||
.arg("build")
|
||||
.arg("--lib")
|
||||
.arg("--target-dir")
|
||||
.arg("target/test_frida_dll_proxy")
|
||||
.env("DLL_PROXY", format!("target/test_frida_dll_proxy/debug/deps/{}", mylib_name))
|
||||
.env("RUSTFLAGS", "-C link-arg=-Wl,--no-as-needed -C link-arg=-lmylib")
|
||||
.arg("target/test_frida_dll_proxy/lib")
|
||||
.env("DLL_PROXY", format!("target/test_frida_dll_proxy/mylib/debug/{mylib_name}"))
|
||||
.env("FRIDA_CODE", r#"
|
||||
const foo = Module.getExportByName(null, "mylib_foo");
|
||||
Interceptor.replace(foo, new NativeCallback(function () {
|
||||
@ -101,16 +103,17 @@ Interceptor.replace(foo, new NativeCallback(function () {
|
||||
|
||||
assert!(lib_status.success(), "Failed to build dynamic library");
|
||||
|
||||
let target_dir = "target/test_frida_dll_proxy/debug/deps/";
|
||||
fs::rename(format!("{}{}", target_dir, get_lib_name("mylib")), format!("{}{}", target_dir, get_lib_name("mylib-orig"))).expect("Failed to rename original DLL");
|
||||
fs::rename(format!("{}{}", target_dir, get_lib_name("frida_deepfreeze_rs")), format!("{}{}", target_dir, get_lib_name("mylib"))).expect("Failed to rename deepfreeze DLL");
|
||||
let target_dir = "target/test_frida_dll_proxy/mybin/debug/deps/";
|
||||
fs::copy(format!("target/test_frida_dll_proxy/mylib/debug/{}", get_lib_name("mylib")), format!("{target_dir}{}", get_lib_name("mylib-orig"))).expect("Failed to rename original DLL");
|
||||
fs::copy(format!("target/test_frida_dll_proxy/lib/debug/{}", get_lib_name("frida_deepfreeze_rs")), format!("{target_dir}{}", get_lib_name("mylib"))).expect("Failed to rename deepfreeze DLL");
|
||||
|
||||
let bin_status = Command::new("cargo")
|
||||
.arg("run")
|
||||
.arg("--manifest-path")
|
||||
.arg("tests/mybin/Cargo.toml")
|
||||
.arg("--target-dir")
|
||||
.arg("target/test_frida_dll_proxy")
|
||||
.arg("target/test_frida_dll_proxy/mybin")
|
||||
// .env("RUSTFLAGS", "-C link-arg=-Wl,--no-as-needed -C link-arg=-lmylib")
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
|
23
src/main.rs
23
src/main.rs
@ -2,19 +2,26 @@ pub mod injector;
|
||||
#[cfg(feature = "frida")]
|
||||
pub mod frida_handler;
|
||||
|
||||
pub use injector::attach;
|
||||
pub use injector::*;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
|
||||
if args.len() < 2 {
|
||||
eprintln!("Usage: {} <PID>", args[0]);
|
||||
if args.len() >= 2 {
|
||||
if let Ok(pid) = args[1].parse() {
|
||||
attach(pid);
|
||||
return;
|
||||
} else {
|
||||
attach_name(args[1].as_ptr(), args[1].len());
|
||||
return;
|
||||
}
|
||||
} else if let Some(spawn_path) = option_env!("TARGET_SPAWN") {
|
||||
spawn(spawn_path.as_ptr(), spawn_path.len());
|
||||
return;
|
||||
} else if let Some(process_name) = option_env!("TARGET_PROCESS") {
|
||||
attach_name(process_name.as_ptr(), process_name.len());
|
||||
return;
|
||||
}
|
||||
|
||||
let pid: u32 = args[1].parse().unwrap();
|
||||
attach(pid);
|
||||
eprintln!("Usage: {} <PID|Process Name>", args[0]);
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod integration_tests;
|
||||
|
Loading…
x
Reference in New Issue
Block a user