Fix frida_code_file, initial config support

Signed-off-by: Dimitris Zervas <dzervas@dzervas.gr>
This commit is contained in:
Dimitris Zervas 2024-04-14 15:16:40 +03:00
parent 7f9a223c61
commit b6a48d5155
No known key found for this signature in database
11 changed files with 166 additions and 143 deletions

75
Cargo.lock generated
View File

@ -160,6 +160,12 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.8"
@ -231,6 +237,7 @@ dependencies = [
"pretty_assertions",
"serde",
"serde_json",
"toml",
"winapi",
"windows-sys 0.52.0",
]
@ -329,6 +336,12 @@ dependencies = [
"scroll",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "hermit-abi"
version = "0.3.8"
@ -450,6 +463,16 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "ipnet"
version = "2.9.0"
@ -913,6 +936,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -1058,6 +1090,40 @@ dependencies = [
"tokio",
]
[[package]]
name = "toml"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "tower"
version = "0.4.13"
@ -1416,6 +1482,15 @@ version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
[[package]]
name = "winnow"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"

View File

@ -30,6 +30,8 @@ ctor = "0.2.7"
[build-dependencies]
goblin = "0.8.0"
build-target = "0.4"
serde = { version = "1.0", features = ["derive"] }
toml = "0.8.12"
[dev-dependencies]
pretty_assertions = "1.4.0"

View File

@ -1,26 +1,79 @@
use serde::Deserialize;
use std::env;
use std::path::Path;
fn main() {
#[derive(Debug, Deserialize)]
pub struct Hook {
pub name: String,
pub args: Vec<String>,
pub ret: String,
pub code: String,
}
#[derive(Debug, Deserialize)]
pub struct Config {
pub dll_proxy: Option<String>,
pub frida_code: Option<String>,
pub frida_code_file: Option<String>,
pub target_exec: Option<String>,
pub target_process: Option<String>,
pub hooks: Vec<Hook>,
}
impl Default for Config {
fn default() -> Self {
println!("cargo:rerun-if-env-changed=FRIDA_CODE");
println!("cargo:rerun-if-env-changed=FRIDA_CODE_FILE");
println!("cargo:rerun-if-env-changed=DLL_PROXY");
println!("cargo:rerun-if-env-changed=TARGET_PROCESS");
println!("cargo:rerun-if-env-changed=TARGET_SPAWN");
if env::var("FRIDA_CODE").is_err() && env::var("FRIDA_CODE_FILE").is_err() {
panic!("No FRIDA_CODE or FRIDA_CODE_FILE set. Please set one of them.");
Self {
dll_proxy : env::var("DLL_PROXY").ok(),
frida_code : env::var("FRIDA_CODE").ok(),
frida_code_file: env::var("FRIDA_CODE_FILE").ok(),
target_exec : env::var("TARGET_SPAWN").ok(),
target_process : env::var("TARGET_PROCESS").ok(),
hooks: Vec::new(),
}
}
}
if env::var("FRIDA_CODE").is_ok() && env::var("FRIDA_CODE_FILE").is_ok() {
panic!("Both FRIDA_CODE and FRIDA_CODE_FILE set. Please set one of them.");
impl Config {
pub fn get_frida_code(&self) -> String {
if self.frida_code.is_some() && self.frida_code_file.is_some() {
panic!("Both frida_code and frida_code_file set. Please set one of them.");
}
if let Ok(frida_code_file) = env::var("FRIDA_CODE_FILE") {
let frida_code = std::fs::read_to_string(frida_code_file).expect("Failed to read FRIDA_CODE_FILE");
println!("cargo:rustc-env=FRIDA_CODE={}", frida_code);
let code = if let Some(frida_code) = &self.frida_code {
frida_code.clone()
} else if let Some(frida_code_file) = &self.frida_code_file {
std::fs::read_to_string(frida_code_file).expect("Failed to read frida_code_file")
} else {
panic!("No frida_code or frida_code_file set. Please set one of them.");
};
code.replace("\n", "\\n")
}
}
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/process");
fn main() {
println!("cargo:rerun-if-env-changed=CONFIG_FILE");
let config = if let Ok(config_file) = env::var("CONFIG_FILE") {
let config_file = std::fs::read_to_string(config_file).expect("Failed to read CONFIG_FILE");
toml::from_str::<Config>(&config_file).expect("Failed to parse CONFIG_FILE")
} else {
Config::default()
};
println!(r#"cargo:rustc-env=FRIDA_CODE={}"#, config.get_frida_code());
let Some(lib_path) = config.dll_proxy else {
println!("cargo:warning=No dll_proxy set, the resulting library has to be manually injected or compiled into the target binary/process");
return;
};
@ -28,14 +81,19 @@ fn main() {
panic!("Dll proxying mode is only supported on Windows.");
}
dll_proxy_linker_flags(&lib_path, config.hooks);
}
fn dll_proxy_linker_flags(lib_path: &str, _hooks: Vec<Hook>) {
use goblin::Object;
println!("cargo:rerun-if-changed={}", &lib_path);
println!("cargo:rerun-if-changed={lib_path}");
let path = Path::new(&lib_path);
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 object = Object::parse(&lib_bytes).expect(format!("Failed to parse given libary 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::PE(pe) = object else {
panic!("Only PE (.dll) files are supported in this mode.");
@ -45,10 +103,10 @@ fn main() {
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() {
println!("cargo:warning=Exported function: {} => {}-orig.{}", e, lib_name, e);
println!("cargo:rustc-link-arg=/export:{}={}-orig.{}", e, lib_name, e);
println!("cargo:warning=Exported function: {e} => {lib_name}-orig.{e}");
println!("cargo:rustc-link-arg=/export:{e}={lib_name}-orig.{e}");
}
println!("cargo:warning=Expected library name: {}-orig.dll", lib_name);
println!("cargo:rustc-env=LIB_NAME={}-orig.dll", lib_name);
println!("cargo:warning=Expected library name: {lib_name}-orig.dll");
println!("cargo:rustc-env=LIB_NAME={lib_name}-orig.dll");
}

View File

@ -1,48 +0,0 @@

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

View File

@ -1,19 +0,0 @@
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);
}
}
}

View File

@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Other\OtherClass.csproj" />
</ItemGroup>
</Project>

View File

@ -1,11 +0,0 @@
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;
}
}
}

View File

@ -1,7 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Library</OutputType>
<RootNamespace>OtherNamespace</RootNamespace>
</PropertyGroup>
</Project>

View File

@ -1,17 +0,0 @@
# 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
```

View File

@ -9,11 +9,11 @@ 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");
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, pid));
#[cfg(not(windows))]
frida_attach_pid(frida_code, pid);
frida_attach_pid(&frida_code, pid);
}
}