Skip to content

Commit

Permalink
Implement getting all hookable symbols
Browse files Browse the repository at this point in the history
Co-Authored-By: Benedikt Zinn <[email protected]>
Signed-off-by: Mr-Kanister <[email protected]>
  • Loading branch information
Mr-Kanister and BenediktZinn committed Dec 4, 2024
1 parent 9cff386 commit 7deabd2
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 87 deletions.
85 changes: 65 additions & 20 deletions rust/backend/daemon/src/bin/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -27,32 +30,58 @@ struct Args {
pid: i32,
}

async fn test_oat_file_exist(client: &mut ZiofaClient<Channel>, 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<Channel>,
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),
};
println!();
}

async fn test_some_entry_method(client: &mut ZiofaClient<Channel>, 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<Channel>,
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!();
}

Expand Down Expand Up @@ -82,8 +111,12 @@ async fn test_get_configuration(client: &mut ZiofaClient<Channel>, 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(),
}),
}
}
};
Expand Down Expand Up @@ -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.");
Expand Down
4 changes: 2 additions & 2 deletions rust/backend/daemon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
3 changes: 2 additions & 1 deletion rust/backend/daemon/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
46 changes: 27 additions & 19 deletions rust/backend/daemon/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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<PidMessage>,
) -> Result<Response<OatFileExistsResponse>, Status> {
let pid = pid_message.into_inner().pid;
let paths: Vec<String> = 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<GetSymbolsOfProcessRequest>,
) -> Result<Response<SymbolList>, 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<PidMessage>,
) -> Result<Response<SomeEntryMethodResponse>, 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<GetAddressOfSymbolRequest>,
) -> Result<Response<GetAddressOfSymbolResponse>, 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 }))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@
// 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;
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,
}
Expand Down Expand Up @@ -46,49 +45,45 @@ impl From<SymbolError> 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<u64, SymbolError> {
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<Vec<PathBuf>, 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<PathBuf> = 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<PathBuf>,
symbol_name: &str,
process_name: &str,
package_name: &str,
) -> Result<u64, SymbolError> {
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<Vec<String>, 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),
})
}

Expand All @@ -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<BufReader<File>>, JsonSymbol>,
) -> Vec<String> {
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,
Expand All @@ -115,19 +121,20 @@ fn get_symbol_address_from_json(
}

fn get_oatdump_contents(
) -> Result<StreamDeserializer<'static, IoRead<BufReader<File>>, Symbol>, SymbolError> {
) -> Result<StreamDeserializer<'static, IoRead<BufReader<File>>, 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::<Symbol>())
Ok(serde_json::Deserializer::from_reader(json_reader).into_iter::<JsonSymbol>())
}

fn get_symbol_address(section_address: u64, symbol: Symbol) -> Result<u64, SymbolError> {
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<u64, SymbolError> {
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)
}
Loading

0 comments on commit 7deabd2

Please sign in to comment.