Add ability to spawn or attach by process name

Signed-off-by: Dimitris Zervas <dzervas@dzervas.gr>
This commit is contained in:
Dimitris Zervas
2024-04-15 21:49:55 +03:00
parent b6a48d5155
commit ff5a7f152f
5 changed files with 174 additions and 49 deletions

View File

@ -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() });
}
}

View File

@ -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()));
}
}

View File

@ -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();

View File

@ -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;