From b9e461d6d16c4380f34d3ccc0497acbf1d67def2 Mon Sep 17 00:00:00 2001 From: Jacob Latonis Date: Tue, 9 Jan 2024 19:46:27 -0600 Subject: [PATCH] feat: rpath_present function for querying rpaths --- yara-x/src/modules/macho/mod.rs | 39 +++++++++++++++- yara-x/src/modules/macho/tests/mod.rs | 64 +++++++++++++++++++++------ yara-x/src/wasm/builder.rs | 22 ++++----- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/yara-x/src/modules/macho/mod.rs b/yara-x/src/modules/macho/mod.rs index c5ce79cd8..024aad1a9 100644 --- a/yara-x/src/modules/macho/mod.rs +++ b/yara-x/src/modules/macho/mod.rs @@ -2836,7 +2836,7 @@ fn ep_for_arch_subtype( } /// The function for checking if any dylib name present in the main Mach-O or embedded Mach-O files -/// contain a dylib wit +/// contain a dylib with the desired name /// /// # Arguments /// @@ -2875,6 +2875,43 @@ fn dylibs_present( Some(false) } +/// The function for checking if any rpath present in the main Mach-O or embedded Mach-O files +/// contain an rpath with the desired path +/// +/// # Arguments +/// +/// * `ctx`: A mutable reference to the scanning context. +/// * `rpath`: The name of the dylib to check if present +/// +/// # Returns +/// +/// An `Option` containing if the path is found +#[module_export(name = "rpath_present")] +fn rpaths_present(ctx: &ScanContext, rpath: RuntimeString) -> Option { + let macho = ctx.module_output::()?; + let expected_rpath = rpath.as_bstr(ctx); + + for rp in macho.rpaths.iter() { + if rp.path.as_ref().is_some_and(|path| { + expected_rpath.eq_ignore_ascii_case(path.as_bytes()) + }) { + return Some(true); + } + } + + for file in macho.file.iter() { + for rp in file.rpaths.iter() { + if rp.path.as_ref().is_some_and(|path| { + expected_rpath.eq_ignore_ascii_case(path.as_bytes()) + }) { + return Some(true); + } + } + } + + Some(false) +} + /// The primary function for processing a Mach-O file, extracting its /// information and populating a `Macho` protobuf object with the extracted /// data. diff --git a/yara-x/src/modules/macho/tests/mod.rs b/yara-x/src/modules/macho/tests/mod.rs index 9ed296f07..e7db75d02 100644 --- a/yara-x/src/modules/macho/tests/mod.rs +++ b/yara-x/src/modules/macho/tests/mod.rs @@ -415,10 +415,14 @@ fn test_swap_entry_point_command() { #[test] fn test_macho_module() { - let macho_data = create_binary_from_zipped_ihex( + let tiny_universal_macho_data = create_binary_from_zipped_ihex( "src/modules/macho/tests/testdata/tiny_universal.in.zip", ); + let x86_macho_data = create_binary_from_zipped_ihex( + "src/modules/macho/tests/testdata/macho_x86_file.in.zip", + ); + rule_true!( r#" import "macho" @@ -469,7 +473,7 @@ fn test_macho_module() { macho.file_index_for_arch(0x00000007) == 0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -480,7 +484,7 @@ fn test_macho_module() { macho.file_index_for_arch(0x01000007) == 1 } "#, - &macho_data + &tiny_universal_macho_data ); rule_false!( @@ -491,7 +495,7 @@ fn test_macho_module() { macho.file_index_for_arch(0x00000008) == 0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -513,7 +517,7 @@ fn test_macho_module() { macho.file_index_for_arch(0x00000007, 0x00000003) == 0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -524,7 +528,7 @@ fn test_macho_module() { macho.file_index_for_arch(16777223, 2147483651) == 1 } "#, - &macho_data + &tiny_universal_macho_data ); rule_false!( @@ -535,7 +539,7 @@ fn test_macho_module() { macho.file_index_for_arch(0x00000008, 0x00000004) == 0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -546,7 +550,7 @@ fn test_macho_module() { not defined macho.file_index_for_arch(0x00000008, 0x00000004) } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -568,7 +572,7 @@ fn test_macho_module() { macho.entry_point_for_arch(0x00000007) == 0x00001EE0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -579,7 +583,7 @@ fn test_macho_module() { macho.entry_point_for_arch(0x01000007) == 0x00004EE0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -590,7 +594,7 @@ fn test_macho_module() { macho.entry_point_for_arch(0x00000007, 0x00000003) == 0x00001EE0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -601,7 +605,7 @@ fn test_macho_module() { macho.entry_point_for_arch(16777223, 2147483651) == 0x00004EE0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_false!( @@ -612,7 +616,7 @@ fn test_macho_module() { macho.entry_point_for_arch(0x00000008, 0x00000003) == 0x00001EE0 } "#, - &macho_data + &tiny_universal_macho_data ); rule_true!( @@ -644,6 +648,38 @@ fn test_macho_module() { macho.dylib_present("/usr/lib/libSystem.B.dylib") } "#, - &macho_data + &tiny_universal_macho_data + ); + + rule_false!( + r#" + import "macho" + rule test { + condition: + macho.rpath_present("totally not present rpath") + } + "# + ); + + rule_false!( + r#" + import "macho" + rule macho_test { + condition: + macho.rpath_present("@loader_path/../Frameworks") + } + "#, + &tiny_universal_macho_data + ); + + rule_true!( + r#" + import "macho" + rule macho_test { + condition: + macho.rpath_present("@loader_path/../Frameworks") + } + "#, + &x86_macho_data ); } diff --git a/yara-x/src/wasm/builder.rs b/yara-x/src/wasm/builder.rs index b9229a84b..c6de801ea 100644 --- a/yara-x/src/wasm/builder.rs +++ b/yara-x/src/wasm/builder.rs @@ -470,38 +470,38 @@ mod tests { assert_eq!( text, r#"(module - (func (;151;) (type 1) (result i32) + (func (;152;) (type 1) (result i32) i32.const 0 global.set 2 i32.const 0 global.set 3 - call 152 call 153 + call 154 global.get 3 ) - (func (;152;) (type 0) - block ;; label = @1 - call 154 - end + (func (;153;) (type 0) block ;; label = @1 call 155 end - ) - (func (;153;) (type 0) block ;; label = @1 call 156 end ) (func (;154;) (type 0) - i32.const 4 + block ;; label = @1 + call 157 + end ) (func (;155;) (type 0) - i32.const 5 + i32.const 4 ) (func (;156;) (type 0) + i32.const 5 + ) + (func (;157;) (type 0) i32.const 6 ) - (export "main" (func 151)) + (export "main" (func 152)) )"# ); }