ditch non-windows dll proxying and split the code
Signed-off-by: Dimitris Zervas <dzervas@dzervas.gr>
This commit is contained in:
parent
7c8105fc47
commit
a5a0153d31
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -88,6 +88,12 @@ version = "2.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "build-target"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "832133bbabbbaa9fbdba793456a2827627a7d2b8fb96032fa1e7666d7895832b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.15.3"
|
version = "3.15.3"
|
||||||
@ -216,6 +222,7 @@ dependencies = [
|
|||||||
name = "frida-deepfreeze-rs"
|
name = "frida-deepfreeze-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"build-target",
|
||||||
"ctor",
|
"ctor",
|
||||||
"frida",
|
"frida",
|
||||||
"goblin",
|
"goblin",
|
||||||
|
@ -29,7 +29,7 @@ ctor = "0.2.7"
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
goblin = "0.8.0"
|
goblin = "0.8.0"
|
||||||
|
build-target = "0.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.0"
|
||||||
# mylib = { path = "tests/mylib" }
|
|
||||||
|
80
build.rs
80
build.rs
@ -1,6 +1,4 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Write;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -8,91 +6,35 @@ fn main() {
|
|||||||
println!("cargo:rerun-if-env-changed=DLL_PROXY");
|
println!("cargo:rerun-if-env-changed=DLL_PROXY");
|
||||||
|
|
||||||
let Ok(lib_path) = env::var("DLL_PROXY") else {
|
let Ok(lib_path) = env::var("DLL_PROXY") else {
|
||||||
println!("cargo:warning=No DLL_PROXY set, the resulting library has to be manually injected or compiled into the target binary");
|
println!("cargo:warning=No DLL_PROXY set, the resulting library has to be manually injected or compiled into the target binary/process");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if build_target::target_os() != Ok(build_target::Os::Windows) {
|
||||||
|
panic!("Dll proxying mode is only supported on Windows.");
|
||||||
|
}
|
||||||
|
|
||||||
use goblin::Object;
|
use goblin::Object;
|
||||||
println!("cargo:rerun-if-changed={}", &lib_path);
|
println!("cargo:rerun-if-changed={}", &lib_path);
|
||||||
|
|
||||||
let path = std::path::Path::new(&lib_path);
|
let path = Path::new(&lib_path);
|
||||||
let lib_filename = path.file_name().unwrap().to_str().unwrap();
|
let lib_filename = path.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
let lib_bytes = std::fs::read(path).expect(format!("Failed to open given library file {}", &lib_filename).as_str());
|
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 = Object::parse(&lib_bytes).expect(format!("Failed to parse given libary file {}", &lib_filename).as_str());
|
||||||
|
|
||||||
let (exports, lib_name): (Vec<&str>, String) = match object {
|
let Object::PE(pe) = object else {
|
||||||
#[cfg(target_os = "windows")]
|
panic!("Only PE (.dll) files are supported in this mode.");
|
||||||
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", ""))
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
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", ""))
|
|
||||||
},
|
|
||||||
#[cfg(target_os = "darwin")]
|
|
||||||
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);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
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", "");
|
||||||
|
|
||||||
for e in exports.iter() {
|
for e in exports.iter() {
|
||||||
println!("cargo:warning=Exported function: {} => {}-orig.{}", e, lib_name, e);
|
println!("cargo:warning=Exported function: {} => {}-orig.{}", e, lib_name, e);
|
||||||
println!("cargo:rustc-link-arg=/export:{}={}-orig.{}", e, lib_name, e);
|
println!("cargo:rustc-link-arg=/export:{}={}-orig.{}", e, lib_name, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
let symbols_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("symbols.rs");
|
|
||||||
let mut symbols = File::create(&symbols_path).unwrap();
|
|
||||||
println!("cargo:rerun-if-changed={:?}", symbols_path);
|
|
||||||
println!("cargo:rustc-cfg=symbols");
|
|
||||||
|
|
||||||
let lib_name = if lib_name.starts_with("lib") {
|
|
||||||
lib_name.replacen("lib", "", 1)
|
|
||||||
} else {
|
|
||||||
lib_name.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
writeln!(symbols, "#![allow(dead_code)]").unwrap();
|
|
||||||
|
|
||||||
for e in exports.iter() {
|
|
||||||
writeln!(symbols, "#[no_mangle]").unwrap();
|
|
||||||
writeln!(symbols, r#"pub unsafe extern "C" fn {e}() {{ original::{e}() }}"#).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(symbols, "pub mod original {{").unwrap();
|
|
||||||
writeln!(symbols, "\t#[link(name = \"{}\")]", lib_name).unwrap();
|
|
||||||
writeln!(symbols, "\textern {{").unwrap();
|
|
||||||
for e in exports.iter() {
|
|
||||||
println!("cargo:warning=Exported function: {}", e);
|
|
||||||
// writeln!(symbols, "\t#[no_mangle]").unwrap();
|
|
||||||
writeln!(symbols, "\t\tpub fn {e}();").unwrap();
|
|
||||||
}
|
|
||||||
writeln!(symbols, "\t}}").unwrap();
|
|
||||||
writeln!(symbols, "}}").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("cargo:warning=Expected library name: {}-orig.dll", lib_name);
|
println!("cargo:warning=Expected library name: {}-orig.dll", lib_name);
|
||||||
println!("cargo:rustc-env=LIB_NAME={}-orig.dll", lib_name);
|
println!("cargo:rustc-env=LIB_NAME={}-orig.dll", lib_name);
|
||||||
}
|
}
|
||||||
|
50
src/lib.rs
50
src/lib.rs
@ -2,63 +2,24 @@ pub mod injector;
|
|||||||
#[cfg(feature = "frida")]
|
#[cfg(feature = "frida")]
|
||||||
pub mod frida_handler;
|
pub mod frida_handler;
|
||||||
|
|
||||||
#[cfg(symbols)]
|
|
||||||
pub mod symbols;
|
|
||||||
#[cfg(symbols)]
|
|
||||||
pub use symbols::*;
|
|
||||||
|
|
||||||
pub use injector::attach_self;
|
pub use injector::attach_self;
|
||||||
|
|
||||||
#[cfg(all(unix, not(test)))]
|
|
||||||
use ctor::ctor;
|
|
||||||
|
|
||||||
// During testing we compile a debug binary without `test`.
|
// During testing we compile a debug binary without `test`.
|
||||||
// Enabling `ctor` during testing would hook the test runner and break it.
|
// Enabling `ctor` during testing would hook the test runner and break it.
|
||||||
#[cfg(all(unix, not(test)))]
|
#[cfg(all(unix, not(test)))]
|
||||||
#[ctor]
|
pub mod loader_unix;
|
||||||
fn _start() {
|
|
||||||
println!("[+] frida-deepfreeze-rs library injected");
|
|
||||||
attach_self();
|
|
||||||
}
|
|
||||||
|
|
||||||
// For some reason ctor doesn't work on Windows - it hangs the process
|
|
||||||
// during DeviceManager::obtain. DllMain works fine though.
|
|
||||||
#[cfg(all(windows, not(test)))]
|
|
||||||
use std::ffi::c_void;
|
|
||||||
#[cfg(all(windows, not(test)))]
|
|
||||||
use winapi::um::winnt::DLL_PROCESS_ATTACH;
|
|
||||||
|
|
||||||
#[cfg(all(windows, not(test)))]
|
#[cfg(all(windows, not(test)))]
|
||||||
use winapi::um::libloaderapi::LoadLibraryA;
|
pub mod loader_windows;
|
||||||
|
|
||||||
#[cfg(all(windows, not(test)))]
|
#[cfg(all(windows, not(test)))]
|
||||||
#[no_mangle]
|
pub use loader_windows::DllMain;
|
||||||
#[allow(non_snake_case, unused_variables)]
|
|
||||||
pub extern "system" fn DllMain(dll_module: *mut c_void, call_reason: u32, _: *mut ()) -> bool {
|
|
||||||
match call_reason {
|
|
||||||
DLL_PROCESS_ATTACH => {
|
|
||||||
println!("[+] frida-deepfreeze-rs DLL injected");
|
|
||||||
|
|
||||||
if let Some(lib_name) = option_env!("LIB_NAME") {
|
|
||||||
unsafe { LoadLibraryA(lib_name.as_ptr() as *const i8); }
|
|
||||||
println!("[+] Original DLL {} loaded", lib_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
attach_self();
|
|
||||||
}
|
|
||||||
// Maybe we should detach? Is it useful?
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn get_lib_name(name: &str) -> String {
|
fn get_lib_name(name: &str) -> String {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
return format!("{}.dll", name);
|
return format!("{}.dll", name);
|
||||||
@ -103,7 +64,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(windows)]
|
||||||
fn test_frida_dll_proxy() {
|
fn test_frida_dll_proxy() {
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
let mylib_name = get_lib_name("mylib");
|
let mylib_name = get_lib_name("mylib");
|
||||||
fs::remove_file(format!("target/test_frida_dll_proxy/debug/deps/{}", mylib_name)).unwrap_or_else(|_| ());
|
fs::remove_file(format!("target/test_frida_dll_proxy/debug/deps/{}", mylib_name)).unwrap_or_else(|_| ());
|
||||||
|
|
||||||
|
9
src/loader_unix.rs
Normal file
9
src/loader_unix.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use ctor::ctor;
|
||||||
|
|
||||||
|
use crate::injector::attach_self;
|
||||||
|
|
||||||
|
#[ctor]
|
||||||
|
fn _start() {
|
||||||
|
println!("[+] frida-deepfreeze-rs library injected");
|
||||||
|
attach_self();
|
||||||
|
}
|
27
src/loader_windows.rs
Normal file
27
src/loader_windows.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use std::ffi::c_void;
|
||||||
|
use winapi::um::winnt::DLL_PROCESS_ATTACH;
|
||||||
|
use winapi::um::libloaderapi::LoadLibraryA;
|
||||||
|
|
||||||
|
// For some reason ctor doesn't work on Windows - it hangs the process
|
||||||
|
// during DeviceManager::obtain. DllMain works fine though.
|
||||||
|
// Would be nice to have a single entry point for all platforms.
|
||||||
|
#[no_mangle]
|
||||||
|
#[allow(non_snake_case, unused_variables)]
|
||||||
|
pub extern "system" fn DllMain(dll_module: *mut c_void, call_reason: u32, _: *mut ()) -> bool {
|
||||||
|
match call_reason {
|
||||||
|
DLL_PROCESS_ATTACH => {
|
||||||
|
println!("[+] frida-deepfreeze-rs DLL injected");
|
||||||
|
|
||||||
|
if let Some(lib_name) = option_env!("LIB_NAME") {
|
||||||
|
unsafe { LoadLibraryA(lib_name.as_ptr() as *const i8); }
|
||||||
|
println!("[+] Original DLL {} loaded", lib_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
attach_self();
|
||||||
|
}
|
||||||
|
// Maybe we should detach? Is it useful?
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user