Add ability to spawn or attach by process name
Signed-off-by: Dimitris Zervas <dzervas@dzervas.gr>
This commit is contained in:
@ -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;
|
||||
|
Reference in New Issue
Block a user