diff --git a/rust/backend/daemon/src/bin/cli.rs b/rust/backend/daemon/src/bin/cli.rs index 22c357bf..80e8d8ce 100644 --- a/rust/backend/daemon/src/bin/cli.rs +++ b/rust/backend/daemon/src/bin/cli.rs @@ -5,12 +5,15 @@ // SPDX-License-Identifier: MIT use clap::Parser; -use shared::ziofa::PidMessage; +use shared::ziofa::{ + GetAddressOfSymbolRequest, GetSymbolsOfProcessRequest, +}; use shared::{ config::{Configuration, SysSendmsgConfig, VfsWriteConfig}, ziofa::ziofa_client::ZiofaClient, }; use tonic::transport::Channel; +use tonic::Request; #[derive(Parser, Debug)] struct Args { @@ -27,13 +30,28 @@ struct Args { pid: i32, } -async fn test_oat_file_exist(client: &mut ZiofaClient, pid: i32) { - println!("TEST checking oat_file_exists"); - match client.test_oat_file_exists(PidMessage { pid }).await { - Ok(list_of_oatfiles) => { +async fn test_get_symbols_of_process( + client: &mut ZiofaClient, + pid: i32, + package_name: String, + verbose: bool, +) { + println!("TEST get_symbols_of_process"); + + match client + .get_symbols_of_process(Request::new(GetSymbolsOfProcessRequest { + pid, + package_name, + })) + .await + { + Ok(res) => { + let names = res.into_inner().names; println!("SUCCESS"); - for file in list_of_oatfiles.into_inner().paths { - println!("{:?}", file); + if verbose { + for (i, s) in names.iter().enumerate() { + println!("Symbol {}: {}", i, s); + } } } Err(e) => println!("ERROR: {:?}", e), @@ -41,18 +59,29 @@ async fn test_oat_file_exist(client: &mut ZiofaClient, pid: i32) { println!(); } -async fn test_some_entry_method(client: &mut ZiofaClient, pid: i32) { - println!("TEST checking some_entry_method"); - match client.test_some_entry_method(PidMessage { pid }).await { - Ok(byte_size_of_odex_file) => { - println!("SUCCESS"); - println!( - "Size of odex file in bytes: {}", - byte_size_of_odex_file.into_inner().content_length - ) +async fn test_get_address_of_symbol( + client: &mut ZiofaClient, + name: String, + pid: i32, + package_name: String, +) { + println!("TEST get_address_of_symbol"); + + match client + .get_address_of_symbol(Request::new(GetAddressOfSymbolRequest { + name, + pid, + package_name, + })) + .await + { + Ok(res) => { + let offset = res.into_inner().offset; + println!("SUCCESS: {}", offset); } Err(e) => println!("ERROR: {:?}", e), }; + println!(); } @@ -82,8 +111,12 @@ async fn test_get_configuration(client: &mut ZiofaClient, verbose: bool println!("ERROR: {:?}", e); Configuration { uprobes: vec![], - vfs_write: Some(VfsWriteConfig { entries: std::collections::HashMap::new() }), - sys_sendmsg: Some(SysSendmsgConfig { entries: std::collections::HashMap::new() }), + vfs_write: Some(VfsWriteConfig { + entries: std::collections::HashMap::new(), + }), + sys_sendmsg: Some(SysSendmsgConfig { + entries: std::collections::HashMap::new(), + }), } } }; @@ -135,8 +168,20 @@ async fn main() { let config = test_get_configuration(&mut client, args.verbose).await; test_set_configuration(&mut client, config).await; test_list_processes(&mut client, args.verbose).await; - test_oat_file_exist(&mut client, args.pid).await; - test_some_entry_method(&mut client, args.pid).await; + test_get_symbols_of_process( + &mut client, + args.pid, + "de.amosproj3.ziofa".to_string(), + args.verbose, + ) + .await; + test_get_address_of_symbol( + &mut client, + "java.lang.String uniffi.shared.UprobeConfig.component1()".to_string(), + args.pid, + "de.amosproj3.ziofa".to_string(), + ) + .await; if !args.verbose { println!("Note: To view verbose output, pass the \"-v\" flag."); diff --git a/rust/backend/daemon/src/lib.rs b/rust/backend/daemon/src/lib.rs index 862639cb..3e2e0f1b 100644 --- a/rust/backend/daemon/src/lib.rs +++ b/rust/backend/daemon/src/lib.rs @@ -13,10 +13,10 @@ mod procfs_utils; mod server; mod features; -mod symbols_stuff; +mod symbols; mod collector; -mod symbols_stuff_helpers; +mod symbols_helpers; pub async fn run_server() { helpers::bump_rlimit(); diff --git a/rust/backend/daemon/src/main.rs b/rust/backend/daemon/src/main.rs index 75d32696..812a6585 100644 --- a/rust/backend/daemon/src/main.rs +++ b/rust/backend/daemon/src/main.rs @@ -13,7 +13,8 @@ mod procfs_utils; mod server; mod features; mod collector; -mod symbols_stuff; +mod symbols; +mod symbols_helpers; #[tokio::main] async fn main() { diff --git a/rust/backend/daemon/src/server.rs b/rust/backend/daemon/src/server.rs index 09572802..7167e245 100644 --- a/rust/backend/daemon/src/server.rs +++ b/rust/backend/daemon/src/server.rs @@ -6,18 +6,20 @@ // SPDX-License-Identifier: MIT use crate::collector::MultiCollector; -use crate::symbols_stuff::{get_symbol_offset_for_function_of_process, SymbolError}; +use crate::symbols::{self, get_symbol_offset_for_function_of_process}; use crate::{ configuration, constants, counter::Counter, ebpf_utils::{EbpfErrorWrapper, State}, procfs_utils::{list_processes, ProcErrorWrapper}, - symbols_stuff::get_odex_files_for_pid, }; use async_broadcast::{broadcast, Receiver, Sender}; use aya::Ebpf; use aya_log::EbpfLogger; -use shared::ziofa::{Event, OatFileExistsResponse, PidMessage, SomeEntryMethodResponse}; +use shared::ziofa::{ + Event, GetAddressOfSymbolRequest, GetAddressOfSymbolResponse, GetSymbolsOfProcessRequest, + SymbolList, +}; use shared::{ config::Configuration, counter::counter_server::CounterServer, @@ -26,7 +28,6 @@ use shared::{ CheckServerResponse, ProcessList, SetConfigurationResponse, }, }; -use std::path::PathBuf; use std::{ops::DerefMut, sync::Arc}; use tokio::join; use tokio::sync::Mutex; @@ -115,25 +116,32 @@ impl Ziofa for ZiofaImpl { Ok(Response::new(self.channel.rx.clone())) } - async fn test_oat_file_exists( + async fn get_symbols_of_process( &self, - pid_message: Request, - ) -> Result, Status> { - let pid = pid_message.into_inner().pid; - let paths: Vec = get_odex_files_for_pid(pid).expect("couldn't get odex files") - .into_iter() - .map(|path_thing: PathBuf| path_thing.to_str().unwrap().to_string()) - .collect(); - Ok(Response::new(OatFileExistsResponse { paths })) + request: Request, + ) -> Result, Status> { + let process = request.into_inner(); + let pid = process.pid; + let package_name = process.package_name; + + Ok(Response::new(SymbolList { + names: symbols::get_symbols_of_pid(pid, &package_name).await?, + })) } - async fn test_some_entry_method( + async fn get_address_of_symbol( &self, - pid_message: Request, - ) -> Result, Status> { - let pid = pid_message.into_inner().pid; - let content_length = get_symbol_offset_for_function_of_process(pid, "ziofa", "java.lang.String uniffi.shared.UprobeConfig.component1()").await.map_err(SymbolError::from)?; - Ok(Response::new(SomeEntryMethodResponse { content_length })) + request: Request, + ) -> Result, Status> { + let request_inner = request.into_inner(); + let symbol_name = request_inner.name; + let pid = request_inner.pid; + let package_name = request_inner.package_name; + + let offset = + get_symbol_offset_for_function_of_process(pid, &package_name, &symbol_name).await?; + + Ok(Response::new(GetAddressOfSymbolResponse { offset })) } } diff --git a/rust/backend/daemon/src/symbols_stuff.rs b/rust/backend/daemon/src/symbols.rs similarity index 64% rename from rust/backend/daemon/src/symbols_stuff.rs rename to rust/backend/daemon/src/symbols.rs index 940e8a96..c585c296 100644 --- a/rust/backend/daemon/src/symbols_stuff.rs +++ b/rust/backend/daemon/src/symbols.rs @@ -4,8 +4,7 @@ // SPDX-License-Identifier: MIT use crate::constants::OATDUMP_PATH; -use crate::symbols_stuff_helpers; -use procfs::process::{MMapPath, Process}; +use crate::symbols_helpers::{self, get_odex_files_for_pid}; use procfs::ProcError; use serde::{Deserialize, Serialize}; use serde_json::de::IoRead; @@ -13,11 +12,11 @@ use serde_json::StreamDeserializer; use std::fs::File; use std::io::BufReader; use std::path::PathBuf; -use symbols_stuff_helpers::{generate_json_oatdump, get_section_address}; +use symbols_helpers::{generate_json_oatdump, get_section_address}; use thiserror::Error; #[derive(Serialize, Deserialize, Debug)] -struct Symbol { +struct JsonSymbol { method: String, offset: String, } @@ -46,49 +45,45 @@ impl From for tonic::Status { pub async fn get_symbol_offset_for_function_of_process( pid: i32, - process_name: &str, + package_name: &str, symbol_name: &str, ) -> Result { let odex_file_paths = get_odex_files_for_pid(pid)?; - parse_odex_files_for_process(&odex_file_paths, symbol_name, process_name).await -} - -pub fn get_odex_files_for_pid(pid: i32) -> Result, SymbolError> { - // get from : /proc/pid/maps -> oat directory (directory with all the odex files) - - let process = Process::new(pid)?; - let maps = process.maps()?; - let all_files: Vec = maps - .iter() - .filter_map(|mm_map| match mm_map.clone().pathname { - MMapPath::Path(path) => Some(path), - _ => None, - }) - .filter(|path: &PathBuf| path.to_str().unwrap().contains(".odex")) - .collect(); - match all_files.len() != 0 { - true => Ok(all_files), - false => Err(SymbolError::Other { - text: format!("Could not find oat file for process with pid: {}", pid), - }), - } + parse_odex_files_for_process(&odex_file_paths, symbol_name, package_name).await } async fn parse_odex_files_for_process( odex_file_paths: &Vec, symbol_name: &str, - process_name: &str, + package_name: &str, ) -> Result { for odex_file_path in odex_file_paths { // TODO: is this really the way... i doubt it - if !odex_file_path.to_str().unwrap().contains(process_name) { + if !odex_file_path.to_str().unwrap().contains(package_name) { continue; } return Ok(parse_odex_file(odex_file_path, symbol_name).await?); } Err(SymbolError::Other { - text: format!("no oat file found for function-name: {}", process_name), + text: format!("no oat file found for package-name: {}", package_name), + }) +} + +pub async fn get_symbols_of_pid(pid: i32, package_name: &str) -> Result, SymbolError> { + let odex_file_paths = get_odex_files_for_pid(pid)?; + for odex_file_path in odex_file_paths { + // TODO: is this really the way... i doubt it + if !odex_file_path.to_str().unwrap().contains(package_name) { + continue; + } + generate_json_oatdump(&odex_file_path).await?; + let outdump_contents = get_oatdump_contents()?; + return Ok(get_symbols_from_json(outdump_contents)); + } + + Err(SymbolError::Other { + text: format!("no oat file found for package-name: {}", package_name), }) } @@ -98,6 +93,17 @@ async fn parse_odex_file(odex_file_path: &PathBuf, symbol_name: &str) -> Result< get_symbol_address_from_json(symbol_name, section_address) } +fn get_symbols_from_json( + outdump_contents: StreamDeserializer<'_, IoRead>, JsonSymbol>, +) -> Vec { + outdump_contents + .filter_map(|c| match c { + Ok(symbol) => Some(symbol.method), + Err(_) => None, + }) + .collect() +} + fn get_symbol_address_from_json( symbol_name: &str, section_address: u64, @@ -115,19 +121,20 @@ fn get_symbol_address_from_json( } fn get_oatdump_contents( -) -> Result>, Symbol>, SymbolError> { +) -> Result>, JsonSymbol>, SymbolError> { let json_file = File::open(OATDUMP_PATH)?; let json_reader = BufReader::new(json_file); - Ok(serde_json::Deserializer::from_reader(json_reader).into_iter::()) + Ok(serde_json::Deserializer::from_reader(json_reader).into_iter::()) } -fn get_symbol_address(section_address: u64, symbol: Symbol) -> Result { - let symbol_address = u64::from_str_radix(symbol.offset.strip_prefix("0x").unwrap(), 16).unwrap() ; - if symbol_address == 0{ +fn get_symbol_address(section_address: u64, symbol: JsonSymbol) -> Result { + let symbol_address = + u64::from_str_radix(symbol.offset.strip_prefix("0x").unwrap(), 16).unwrap(); + if symbol_address == 0 { return Err(SymbolError::SymbolIsNotCompiled { symbol: symbol.method.to_string(), }); } - + Ok(symbol_address + section_address) } diff --git a/rust/backend/daemon/src/symbols_stuff_helpers.rs b/rust/backend/daemon/src/symbols_helpers.rs similarity index 53% rename from rust/backend/daemon/src/symbols_stuff_helpers.rs rename to rust/backend/daemon/src/symbols_helpers.rs index 1c5e3e6a..bda3f45c 100644 --- a/rust/backend/daemon/src/symbols_stuff_helpers.rs +++ b/rust/backend/daemon/src/symbols_helpers.rs @@ -1,17 +1,23 @@ +// SPDX-FileCopyrightText: 2024 Benedikt Zinn +// SPDX-FileCopyrightText: 2024 Robin Seidl +// +// SPDX-License-Identifier: MIT + use std::path::PathBuf; +use procfs::process::{MMapPath, Process}; use tokio::process::Command; use std::fs::File; use object::{Object, ObjectSymbol, ReadCache}; use std::io::Error; use crate::constants::OATDUMP_PATH; -use crate::symbols_stuff::SymbolError; +use crate::symbols::SymbolError; pub async fn generate_json_oatdump(path: &PathBuf) -> Result<(), SymbolError> { let _oatdump_status = Command::new("oatdump") .args(vec![ format!("--output={}", OATDUMP_PATH).as_str(), "--dump-method-and-offset-as-json", - format!("--oat-file={}", path.to_str().unwrap().to_string()).as_str(), + format!("--oat-file={}", path.to_str().unwrap()).as_str(), ]) .spawn()? .wait() @@ -29,6 +35,27 @@ pub async fn get_section_address(oat_path: &PathBuf) -> Result { .await? } +pub fn get_odex_files_for_pid(pid: i32) -> Result, SymbolError> { + // get from : /proc/pid/maps -> oat directory (directory with all the odex files) + + let process = Process::new(pid)?; + let maps = process.maps()?; + let all_files: Vec = maps + .iter() + .filter_map(|mm_map| match mm_map.clone().pathname { + MMapPath::Path(path) => Some(path), + _ => None, + }) + .filter(|path: &PathBuf| path.to_str().unwrap().contains(".odex")) + .collect(); + match !all_files.is_empty() { + true => Ok(all_files), + false => Err(SymbolError::Other { + text: format!("Could not find oat file for process with pid: {}", pid), + }), + } +} + fn get_symbol_address_from_oat(path: &PathBuf, symbol_name: &str) -> Result { let file = File::open(path)?; let file_cache = ReadCache::new(file); diff --git a/rust/shared/proto/ziofa.proto b/rust/shared/proto/ziofa.proto index c9c364b7..6586d7be 100644 --- a/rust/shared/proto/ziofa.proto +++ b/rust/shared/proto/ziofa.proto @@ -20,23 +20,33 @@ service Ziofa { rpc InitStream(google.protobuf.Empty) returns (stream Event) {} // all Responses genereated by the ebpf-programms are send via this stream - rpc TestOatFileExists(PidMessage) returns (OatFileExistsResponse){} - rpc TestSomeEntryMethod(PidMessage) returns (SomeEntryMethodResponse){} + rpc GetSymbolsOfProcess(GetSymbolsOfProcessRequest) returns (SymbolList){} + rpc GetAddressOfSymbol(GetAddressOfSymbolRequest) returns (GetAddressOfSymbolResponse){} } -message PidMessage{ +message GetSymbolsOfProcessRequest { int32 pid = 1; + string package_name = 2; +} + +message SymbolList { + repeated string names = 1; } -message OatFileExistsResponse{ - repeated string paths = 1; +message GetAddressOfSymbolRequest { + string name = 1; + int32 pid = 2; + string package_name = 3; } -message SomeEntryMethodResponse{ - uint64 content_length = 1; +message GetAddressOfSymbolResponse { + uint64 offset = 1; } +message PidMessage{ + int32 pid = 1; +} message CheckServerResponse { // TODO