Test injectable DLL for windows

Signed-off-by: Dimitris Zervas <dzervas@dzervas.gr>
This commit is contained in:
Dimitris Zervas 2024-04-13 04:41:03 +03:00
parent dafcf5d0eb
commit 21f7f06f13
No known key found for this signature in database
6 changed files with 89 additions and 118 deletions

45
Cargo.lock generated
View File

@ -72,7 +72,7 @@ dependencies = [
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"syn 2.0.51", "syn",
"which", "which",
] ]
@ -132,16 +132,6 @@ dependencies = [
"libloading", "libloading",
] ]
[[package]]
name = "csbindgen"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf70eb656f35e0e6956cbde31c66431c53d8a546823489719099c71525767a9c"
dependencies = [
"regex",
"syn 1.0.109",
]
[[package]] [[package]]
name = "ctor" name = "ctor"
version = "0.2.7" version = "0.2.7"
@ -149,7 +139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.51", "syn",
] ]
[[package]] [[package]]
@ -226,12 +216,10 @@ dependencies = [
name = "frida-deepfreeze-rs" name = "frida-deepfreeze-rs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"csbindgen",
"ctor", "ctor",
"frida", "frida",
"goblin", "goblin",
"lazy_static", "lazy_static",
"mylib",
"pretty_assertions", "pretty_assertions",
"serde", "serde",
"serde_json", "serde_json",
@ -573,10 +561,6 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "mylib"
version = "0.1.0"
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.3" version = "7.1.3"
@ -635,7 +619,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.51", "syn",
] ]
[[package]] [[package]]
@ -679,7 +663,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn 2.0.51", "syn",
] ]
[[package]] [[package]]
@ -883,7 +867,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.51", "syn",
] ]
[[package]] [[package]]
@ -903,7 +887,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.51", "syn",
] ]
[[package]] [[package]]
@ -972,17 +956,6 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.51" version = "2.0.51"
@ -1028,7 +1001,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.51", "syn",
] ]
[[package]] [[package]]
@ -1201,7 +1174,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.51", "syn",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -1235,7 +1208,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.51", "syn",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]

View File

@ -12,7 +12,6 @@ path = "src/main.rs"
[features] [features]
default = ["frida"] default = ["frida"]
dotnet = ["dep:csbindgen"]
frida = ["dep:frida", "dep:lazy_static", "dep:serde", "dep:serde_json"] frida = ["dep:frida", "dep:lazy_static", "dep:serde", "dep:serde_json"]
[dependencies] [dependencies]
@ -30,8 +29,7 @@ ctor = "0.2.7"
[build-dependencies] [build-dependencies]
goblin = "0.8.0" goblin = "0.8.0"
csbindgen = { version = "1.9.1", optional = true}
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.4.0" pretty_assertions = "1.4.0"
mylib = { path = "tests/mylib" } # mylib = { path = "tests/mylib" }

View File

@ -2,14 +2,13 @@ use std::env;
use std::io::Write; use std::io::Write;
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
#[cfg(feature = "dotnet")]
use csbindgen;
fn main() { fn main() {
println!("cargo:rerun-if-env-changed=FRIDA_CODE"); println!("cargo:rerun-if-env-changed=FRIDA_CODE");
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");
return; return;
}; };
@ -72,7 +71,7 @@ fn main() {
writeln!(symbols, "extern {{").unwrap(); writeln!(symbols, "extern {{").unwrap();
for e in exports.iter() { for e in exports.iter() {
println!("cargo:warning=Exported function: {}", e); println!("cargo:warning=Exported function: {}", e);
// writeln!(symbols, "\t#[no_mangle]").unwrap(); writeln!(symbols, "\t#[no_mangle]").unwrap();
writeln!(symbols, "\tpub fn {}();", e).unwrap(); writeln!(symbols, "\tpub fn {}();", e).unwrap();
} }
writeln!(symbols, "}}").unwrap(); writeln!(symbols, "}}").unwrap();
@ -80,15 +79,4 @@ fn main() {
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);
#[cfg(feature = "dotnet")]
{
let lib_path = concat!(env!("CARGO_MANIFEST_DIR"), "/src/lib.rs");
let csharp_file = concat!(env!("CARGO_MANIFEST_DIR"), "/dotnet/NativeMethods.g.cs");
csbindgen::Builder::default()
.input_extern_file(lib_path)
.csharp_dll_name("deepfreeze")
.generate_csharp_file(csharp_file)
.unwrap();
}
} }

View File

@ -88,29 +88,29 @@ impl ScriptHandler for Handler {
} }
} }
#[cfg(test)] // #[cfg(test)]
mod tests { // mod tests {
use super::*; // use super::*;
use pretty_assertions::assert_eq; // use pretty_assertions::assert_eq;
#[link(name = "mylib", kind = "dylib")] // #[link(name = "mylib", kind = "dylib")]
extern { // extern {
fn mylib_foo() -> u8; // fn mylib_foo() -> u8;
} // }
#[test] // #[test]
fn test_attach_pid() { // fn test_attach_pid() {
assert_eq!(10, unsafe { mylib_foo() }); // assert_eq!(10, unsafe { mylib_foo() });
let frida_script = r#" // let frida_script = r#"
const foo = Module.getExportByName(null, "mylib_foo"); // const foo = Module.getExportByName(null, "mylib_foo");
Interceptor.replace(foo, new NativeCallback(function () { // Interceptor.replace(foo, new NativeCallback(function () {
console.log("replaced foo() called"); // console.log("replaced foo() called");
return 20; // return 20;
}, "uint8", [])); // }, "uint8", []));
"#; // "#;
attach_pid(frida_script, 0); // attach_pid(frida_script, 0);
assert_eq!(20, unsafe { mylib_foo() }); // assert_eq!(20, unsafe { mylib_foo() });
} // }
} // }

View File

@ -1,13 +1,7 @@
#[cfg(all(unix, not(feature = "frida")))] #[cfg(all(not(feature = "frida")))]
compile_error!("Only Frida injection is supported for Unix targets");
#[cfg(all(not(feature = "dotnet"), not(feature = "frida")))]
compile_error!("No injection method is selected - please enable either dotnet (windows-only) and/or frida feature"); compile_error!("No injection method is selected - please enable either dotnet (windows-only) and/or frida feature");
// #[cfg(all(not(windows), feature = "dotnet"))]
// compile_error!("Managed library injection is only supported for Windows target");
#[cfg(feature = "frida")] #[cfg(feature = "frida")]
use crate::frida_handler::attach_pid as frida_attach_pid; use crate::frida_handler::attach_pid as frida_attach_pid;

View File

@ -3,8 +3,11 @@ pub mod injector;
pub mod frida_handler; pub mod frida_handler;
// #[cfg(feature = "dotnet")] // #[cfg(feature = "dotnet")]
// pub mod cs; // pub mod cs;
#[cfg(not(windows))]
pub mod symbols; // #[cfg(not(windows))]
// pub mod symbols;
// #[cfg(not(windows))]
// pub use symbols::*;
pub use injector::attach_self; pub use injector::attach_self;
@ -36,8 +39,10 @@ pub extern "system" fn DllMain(dll_module: *mut c_void, call_reason: u32, _: *mu
DLL_PROCESS_ATTACH => { DLL_PROCESS_ATTACH => {
println!("[+] frida-deepfreeze-rs DLL injected"); println!("[+] frida-deepfreeze-rs DLL injected");
unsafe { LoadLibraryA(env!("LIB_NAME").as_ptr() as *const i8); } if let Some(lib_name) = option_env!("LIB_NAME") {
println!("[+] Original DLL {} loaded", env!("LIB_NAME")); unsafe { LoadLibraryA(lib_name.as_ptr() as *const i8); }
println!("[+] Original DLL {} loaded", lib_name);
}
attach_self(); attach_self();
} }
@ -56,7 +61,7 @@ mod tests {
use std::fs; use std::fs;
#[test] #[test]
#[cfg(feature = "frida")] // #[cfg(all(unix, feature = "frida"))]
fn test_frida_on_load() { fn test_frida_on_load() {
let lib_status = Command::new("cargo") let lib_status = Command::new("cargo")
.arg("build") .arg("build")
@ -71,7 +76,7 @@ mod tests {
}, "uint8", [])); }, "uint8", []));
"#) "#)
.status() .status()
.expect("Failed to build dynamic library"); .unwrap();
assert!(lib_status.success(), "Failed to build dynamic library"); assert!(lib_status.success(), "Failed to build dynamic library");
@ -88,37 +93,50 @@ mod tests {
assert_eq!(bin_status.code().unwrap(), 40, "Failed to replace foo()"); assert_eq!(bin_status.code().unwrap(), 40, "Failed to replace foo()");
} }
#[test] // #[test]
#[cfg(all(windows, feature = "frida"))] // #[cfg(all(windows, feature = "frida"))]
fn test_frida_on_load() { // fn test_frida_on_load() {
let bin_exec = Command::new("cargo") // let mylib_status = Command::new("cargo")
.arg("build") // .arg("build")
.arg("--manifest-path") // .arg("--lib")
.arg("tests/mybin/Cargo.toml") // .arg("--manifest-path")
.arg("--target-dir") // .arg("tests/mylib/Cargo.toml")
.arg("target/test_frida_on_load"); // .arg("--target-dir")
// .arg("target/test_frida_on_load")
// .status()
// .expect("Failed to build mylib");
// assert!(mylib_status.success(), "Failed to build mylib");
let lib_status = Command::new("cargo") // let lib_status = Command::new("cargo")
.arg("build") // .arg("build")
.arg("--lib") // .arg("--lib")
.arg("--target-dir") // .arg("--target-dir")
.arg("target/test_frida_on_load") // .arg("target/test_frida_on_load")
.env("DLL_PROXY", "target/test_frida_on_load/debug/deps/mylib.dll") // .env("DLL_PROXY", "target/test_frida_on_load/debug/deps/mylib.dll")
.env("FRIDA_CODE", r#" // .env("FRIDA_CODE", r#"
const foo = Module.getExportByName(null, "mylib_foo"); // const foo = Module.getExportByName(null, "mylib_foo");
Interceptor.replace(foo, new NativeCallback(function () { // Interceptor.replace(foo, new NativeCallback(function () {
console.log("replaced foo() called"); // console.log("replaced foo() called");
return 40; // return 40;
}, "uint8", [])); // }, "uint8", []));
"#) // "#)
.status() // .status()
.expect("Failed to build dynamic library"); // .expect("Failed to build dynamic library");
assert!(lib_status.success(), "Failed to build dynamic library"); // assert!(lib_status.success(), "Failed to build dynamic library");
fs::rename("target/test_frida_on_load/debug/deps/mylib.dll", "target/test_frida_on_load/debug/mylib-orig.dll").expect("Failed to rename original DLL"); // fs::rename("target/test_frida_on_load/debug/deps/mylib.dll", "target/test_frida_on_load/debug/mylib-orig.dll").expect("Failed to rename original DLL");
fs::rename("target/test_frida_on_load/debug/frida_deepfreeze_rs.dll", "target/test_frida_on_load/debug/mylib.dll").expect("Failed to rename deepfreeze DLL"); // fs::rename("target/test_frida_on_load/debug/frida_deepfreeze_rs.dll", "target/test_frida_on_load/debug/mylib.dll").expect("Failed to rename deepfreeze DLL");
let bin_status = bin_exec.status().expect("Failed to build mybin");
assert_eq!(bin_status.code().unwrap(), 40, "Failed to replace foo()"); // let bin_status = Command::new("cargo")
} // .arg("run")
// .arg("--manifest-path")
// .arg("tests/mybin/Cargo.toml")
// .arg("--target-dir")
// .arg("target/test_frida_on_load")
// .status()
// .expect("Failed to build mybin");
// assert_eq!(bin_status.code().unwrap(), 40, "Failed to replace foo()");
// }
} }