diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 27ae1ab..2a62b92 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -42,4 +42,4 @@ jobs:
# - name: Run tests - frida
# if: runner.os == 'windows-latest'
- # run: cargo test --verbose --no-default-features --features managed_lib
+ # run: cargo test --verbose --no-default-features --features dotnet
diff --git a/.gitignore b/.gitignore
index 847c890..ccaa143 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,8 @@ __handlers__
/examples/cs/*/obj
/examples/cs/*/bin
*.png~
+*.exe
+*.dll
+/examples/cs/bin
+/examples/cs/obj
+/dotnet
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 0c2abb7..13323bf 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,4 @@
{
- "rust-analyzer.showUnlinkedFileNotification": false
+ "rust-analyzer.cargo.features": "all",
+ "rust-analyzer.check.features": "all"
}
diff --git a/Cargo.lock b/Cargo.lock
index fdf6820..3f66cbf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -72,7 +72,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
- "syn",
+ "syn 2.0.51",
"which",
]
@@ -148,6 +148,16 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+[[package]]
+name = "csbindgen"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c848726dae35e119d20f0aae60950095dc00cc399d7c56620019c47ae1d7b385"
+dependencies = [
+ "regex",
+ "syn 1.0.109",
+]
+
[[package]]
name = "ctor"
version = "0.2.7"
@@ -155,7 +165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c"
dependencies = [
"quote",
- "syn",
+ "syn 2.0.51",
]
[[package]]
@@ -268,6 +278,7 @@ dependencies = [
name = "frida-deepfreeze-rs"
version = "0.1.0"
dependencies = [
+ "csbindgen",
"ctor",
"frida",
"goblin",
@@ -691,7 +702,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.51",
]
[[package]]
@@ -759,7 +770,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
dependencies = [
"proc-macro2",
- "syn",
+ "syn 2.0.51",
]
[[package]]
@@ -924,7 +935,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.51",
]
[[package]]
@@ -967,7 +978,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.51",
]
[[package]]
@@ -1018,6 +1029,17 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[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]]
name = "syn"
version = "2.0.51"
@@ -1096,7 +1118,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.51",
]
[[package]]
@@ -1259,7 +1281,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.51",
"wasm-bindgen-shared",
]
@@ -1293,7 +1315,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.51",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
diff --git a/Cargo.toml b/Cargo.toml
index c8feb9c..7a2dd69 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,9 +12,7 @@ path = "src/main.rs"
[features]
default = ["frida"]
-# dll_proxy = []
-managed_lib = ["dep:windows-sys"]
-# unmanaged_lib = [],
+dotnet = ["dep:csbindgen"]
frida = ["dep:frida", "dep:lazy_static", "dep:serde", "dep:serde_json"]
[dependencies]
@@ -32,6 +30,7 @@ ctor = "0.2.6"
[build-dependencies]
goblin = "0.8.0"
+csbindgen = { version = "1.9.0", optional = true}
[dev-dependencies]
pretty_assertions = "1.4.0"
diff --git a/build.rs b/build.rs
index 45641db..5552fa2 100644
--- a/build.rs
+++ b/build.rs
@@ -1,4 +1,6 @@
use std::env;
+#[cfg(feature = "dotnet")]
+use csbindgen;
fn main() {
println!("cargo:rerun-if-env-changed=FRIDA_CODE");
@@ -34,4 +36,15 @@ fn main() {
println!("cargo:warning=Expected library 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();
+ }
}
diff --git a/examples/cs/Example.sln b/examples/cs/Example.sln
new file mode 100644
index 0000000..daaae02
--- /dev/null
+++ b/examples/cs/Example.sln
@@ -0,0 +1,48 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyClass", "My\MyClass.csproj", "{F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OtherClass", "Other\OtherClass.csproj", "{EAA4714F-3F2E-4801-81B7-9BC502347B53}"
+EndProject
+Global
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Debug|x64.Build.0 = Debug|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Debug|x86.Build.0 = Debug|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Release|x64.ActiveCfg = Release|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Release|x64.Build.0 = Release|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Release|x86.ActiveCfg = Release|Any CPU
+ {F480EEA9-B211-4BDF-A364-8B8D1B6F4FCE}.Release|x86.Build.0 = Release|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Debug|x64.Build.0 = Debug|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Debug|x86.Build.0 = Debug|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Release|x64.ActiveCfg = Release|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Release|x64.Build.0 = Release|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Release|x86.ActiveCfg = Release|Any CPU
+ {EAA4714F-3F2E-4801-81B7-9BC502347B53}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/examples/cs/My/MyClass.cs b/examples/cs/My/MyClass.cs
new file mode 100644
index 0000000..0ba4934
--- /dev/null
+++ b/examples/cs/My/MyClass.cs
@@ -0,0 +1,19 @@
+using System;
+using OtherNamespace;
+
+namespace MyNamespace {
+ public class MyClass {
+ // This method will be called by native code inside the target process…
+ public static int MyMethod(String pwzArgument) {
+ System.Console.WriteLine("Hello World from C# {0}", pwzArgument);
+ return 0;
+ }
+
+ public static void Main() {
+ int my = MyMethod("from Main()");
+ System.Console.WriteLine("MyMethod returned {0}", my);
+ int other = OtherNamespace.OtherClass.OtherMethod();
+ System.Console.WriteLine("OtherMethod returned {0}", other);
+ }
+ }
+}
diff --git a/examples/cs/My/MyClass.csproj b/examples/cs/My/MyClass.csproj
new file mode 100644
index 0000000..587dbaf
--- /dev/null
+++ b/examples/cs/My/MyClass.csproj
@@ -0,0 +1,10 @@
+
+
+ net8.0
+ Exe
+
+
+
+
+
+
diff --git a/examples/cs/Other/OtherClass.cs b/examples/cs/Other/OtherClass.cs
new file mode 100644
index 0000000..2ccd8a6
--- /dev/null
+++ b/examples/cs/Other/OtherClass.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace OtherNamespace {
+ public class OtherClass {
+ // This method will be called by native code inside the target process…
+ public static int OtherMethod() {
+ System.Console.WriteLine("Goodbye World from C#");
+ return 1;
+ }
+ }
+}
diff --git a/examples/cs/Other/OtherClass.csproj b/examples/cs/Other/OtherClass.csproj
new file mode 100644
index 0000000..4893ead
--- /dev/null
+++ b/examples/cs/Other/OtherClass.csproj
@@ -0,0 +1,7 @@
+
+
+ net8.0
+ Library
+ OtherNamespace
+
+
diff --git a/examples/cs/README.md b/examples/cs/README.md
new file mode 100644
index 0000000..329bddf
--- /dev/null
+++ b/examples/cs/README.md
@@ -0,0 +1,17 @@
+# C# Example
+
+To compile:
+
+```sh
+sudo pacman -S dotnet-host dotnet-runtime dotnet-sdk
+dotnet build
+```
+
+To run:
+
+```sh
+./My/bin/Debug/net8.0/MyClass
+# or
+sudo pacman -S mono
+mono My/bin/Debug/net8.0/MyClass.dll
+```
diff --git a/src/frida_handler.rs b/src/frida_handler.rs
index 973b71f..561c361 100644
--- a/src/frida_handler.rs
+++ b/src/frida_handler.rs
@@ -1,5 +1,5 @@
#![cfg(feature = "frida")]
-use frida::{DeviceManager, Frida, ScriptHandler, ScriptOption, ScriptRuntime};
+use frida::{DeviceManager, DeviceType, Frida, ScriptHandler, ScriptOption, ScriptRuntime};
use lazy_static::lazy_static;
use serde::Deserialize;
@@ -7,13 +7,13 @@ lazy_static! {
pub static ref FRIDA: Frida = unsafe { Frida::obtain() };
}
-pub fn attach_pid(frida_code: String, pid: u32) {
+pub fn attach_pid(frida_code: &str, pid: u32) {
println!("[+] Injecting into PID: {}", pid);
let device_manager = DeviceManager::obtain(&FRIDA);
println!("[*] Device Manager obtained");
- if let Some(device) = device_manager.enumerate_all_devices().first() {
+ if let Ok(device) = device_manager.get_device_by_type(DeviceType::Local) {
println!("[*] First device: {}", device.get_name());
let session = device.attach(pid).unwrap();
@@ -25,7 +25,7 @@ pub fn attach_pid(frida_code: String, pid: u32) {
.set_runtime(ScriptRuntime::QJS);
println!("[*] Script {}", frida_code);
let script = session
- .create_script(&frida_code, &mut script_option)
+ .create_script(frida_code, &mut script_option)
.unwrap();
script.handle_message(&mut Handler).unwrap();
@@ -110,7 +110,7 @@ mod tests {
}, "uint8", []));
"#;
- attach_pid(frida_script.to_string(), 0);
+ attach_pid(frida_script, 0);
assert_eq!(20, unsafe { mylib_foo() });
}
}
diff --git a/src/injector.rs b/src/injector.rs
index 49e4866..042fa0f 100644
--- a/src/injector.rs
+++ b/src/injector.rs
@@ -2,11 +2,11 @@
#[cfg(all(unix, not(feature = "frida")))]
compile_error!("Only Frida injection is supported for Unix targets");
-#[cfg(all(not(feature = "managed_lib"), not(feature = "frida")))]
-compile_error!("No injection method is selected - please enable either managed_lib (windows-only) and/or frida feature");
+#[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");
-#[cfg(all(not(windows), feature = "managed_lib"))]
-compile_error!("Managed library injection is only supported for Windows target");
+// #[cfg(all(not(windows), feature = "dotnet"))]
+// compile_error!("Managed library injection is only supported for Windows target");
#[cfg(feature = "frida")]
use crate::frida_handler::attach_pid as frida_attach_pid;
@@ -15,7 +15,7 @@ use crate::frida_handler::attach_pid as frida_attach_pid;
pub extern "C" fn attach(pid: u32) {
#[cfg(feature = "frida")]
{
- let frida_code = env!("FRIDA_CODE").to_string();
+ let frida_code = env!("FRIDA_CODE");
#[cfg(windows)]
std::thread::spawn(move || frida_attach_pid(frida_code, pid));
#[cfg(not(windows))]
diff --git a/src/lib.rs b/src/lib.rs
index cd1c1d5..aa3fe7b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,13 +1,15 @@
pub mod injector;
#[cfg(feature = "frida")]
pub mod frida_handler;
+// #[cfg(feature = "dotnet")]
+// pub mod cs;
-pub use injector::{attach, attach_self};
+pub use injector::attach_self;
-#[cfg(all(unix, not(test)))]
+#[cfg(all(unix, not(test), not(feature = "dotnet")))]
use ctor::ctor;
-#[cfg(all(unix, not(test)))]
+#[cfg(all(unix, not(test), not(feature = "dotnet")))]
#[ctor]
fn _start() {
println!("[+] frida-deepfreeze-rs library injected");
@@ -16,27 +18,24 @@ fn _start() {
// 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)))]
+#[cfg(all(any(windows, feature = "dotenv"), not(test)))]
use std::ffi::c_void;
-#[cfg(all(windows, not(test)))]
+#[cfg(all(any(windows, feature = "dotenv"), not(test)))]
use winapi::um::winnt::DLL_PROCESS_ATTACH;
-#[cfg(all(windows, feature = "dll_proxy", not(test)))]
+#[cfg(all(any(windows, feature = "dotenv"), not(test)))]
use winapi::um::libloaderapi::LoadLibraryA;
-#[cfg(all(windows, not(test)))]
+#[cfg(all(any(windows, feature = "dotenv"), not(test)))]
#[no_mangle]
#[allow(non_snake_case, unused_variables)]
-extern "system" fn DllMain(dll_module: *mut c_void, call_reason: u32, _: *mut ()) -> bool {
+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");
- #[cfg(feature = "dll_proxy")]
- {
- unsafe { LoadLibraryA(env!("LIB_NAME").as_ptr() as *const i8); }
- println!("[+] Original DLL {} loaded", env!("LIB_NAME"));
- }
+ unsafe { LoadLibraryA(env!("LIB_NAME").as_ptr() as *const i8); }
+ println!("[+] Original DLL {} loaded", env!("LIB_NAME"));
attach_self();
}
diff --git a/src/win_daemon.rs b/src/win_daemon.rs
new file mode 100644
index 0000000..7175dd7
--- /dev/null
+++ b/src/win_daemon.rs
@@ -0,0 +1,99 @@
+#![cfg(windows)]
+
+use std::ffi::c_void;
+use winapi::shared::minwindef::DWORD;
+use winapi::um::evntprov::*;
+use winapi::um::evntcons::*;
+use winapi::um::evntprov::*;
+use winapi::um::winnt::{EVENT_TRACE_CONTROL_STOP, EVENT_TRACE_FLAG_PROCESS};
+
+pub fn start_daemon() {
+ // Create an event trace session
+ let session_name = "frida-deepfreeze-rs";
+ let session_handle = create_event_trace_session(session_name);
+ if session_handle.is_null() {
+ eprintln!("Failed to create event trace session");
+ return;
+ }
+
+ // Enable process creation events
+ enable_process_creation_events(session_handle);
+
+ // Process events until a termination event is received
+ process_events(session_handle);
+
+ // Stop the event trace session
+ stop_event_trace_session(session_handle);
+}
+
+fn create_event_trace_session(session_name: &str) -> TRACEHANDLE {
+ let session_name = widestring::WideCString::from_str(session_name).expect("Failed to convert session name");
+
+ let mut session_handle: TRACEHANDLE = 0;
+ let status = unsafe {
+ StartTraceW(
+ &mut session_handle,
+ session_name.as_ptr(),
+ ptr::null_mut(),
+ )
+ };
+
+ if status != ERROR_SUCCESS {
+ println!("Failed to start event trace session: {}", status);
+ }
+
+ session_handle
+}
+
+fn enable_process_creation_events(session_handle: TRACEHANDLE) {
+ let status = unsafe {
+ EnableTraceEx2(
+ session_handle,
+ &EVENT_TRACE_GUID_PROCESS,
+ EVENT_CONTROL_CODE_ENABLE_PROVIDER,
+ TRACE_LEVEL_INFORMATION,
+ EVENT_TRACE_FLAG_PROCESS,
+ 0,
+ 0,
+ 0,
+ NULL,
+ )
+ };
+
+ if status != ERROR_SUCCESS {
+ println!("Failed to enable process creation events: {}", status);
+ }
+}
+
+fn process_events(session_handle: TRACEHANDLE) {
+ let mut buffer_size: DWORD = 64 * 1024;
+ let mut buffer = vec![0u8; buffer_size as usize];
+
+ let status = unsafe {
+ ProcessTrace(
+ &mut session_handle,
+ 1,
+ NULL,
+ NULL,
+ )
+ };
+
+ if status != ERROR_SUCCESS && status != ERROR_CANCELLED {
+ println!("Failed to process events: {}", status);
+ }
+}
+
+fn stop_event_trace_session(session_handle: TRACEHANDLE) {
+ let status = unsafe {
+ ControlTraceW(
+ session_handle,
+ NULL,
+ NULL,
+ EVENT_TRACE_CONTROL_STOP,
+ )
+ };
+
+ if status != ERROR_SUCCESS {
+ println!("Failed to stop event trace session: {}", status);
+ }
+}