Skip to content

Commit

Permalink
feat: implement sym_hash() function for mach-o module (#248)
Browse files Browse the repository at this point in the history
Implement the `sym_hash()` function for the mach-o module to hash all of the symbol table entries, if the binary has not been stripped. This did not include new parsing, only utiIizing the entries we already parsed.
  • Loading branch information
latonis authored Nov 21, 2024
1 parent c8dbcb8 commit 260a2c4
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
33 changes: 33 additions & 0 deletions lib/src/modules/macho/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use crate::modules::prelude::*;
use crate::modules::protos::macho::*;
use bstr::BString;
use itertools::Itertools;
use md5::{Digest, Md5};

Expand Down Expand Up @@ -446,6 +447,38 @@ fn import_hash(ctx: &mut ScanContext) -> Option<RuntimeString> {
Some(RuntimeString::new(digest))
}

/// Returns an md5 hash of the symbol table in the mach-o binary
#[module_export]
fn sym_hash(ctx: &mut ScanContext) -> Option<RuntimeString> {
let macho = ctx.module_output::<Macho>()?;
let mut symtab_to_hash = &macho.symtab.entries;

// if there is not a symbtol table in the main Macho, the symbol table of the
// nested file should be hashed
if symtab_to_hash.is_empty() && !macho.file.is_empty() {
symtab_to_hash = &macho.file[0].symtab.entries;
}

// we need to check again as the nested symbol table could be empty too
if symtab_to_hash.is_empty() {
return None;
}

let mut md5_hash: digest::core_api::CoreWrapper<md5::Md5Core> = Md5::new();

let symtab_hash_entries = symtab_to_hash
.iter()
.map(|e| BString::new(e.trim().to_lowercase()))
.unique()
.sorted()
.join(",");

md5_hash.update(symtab_hash_entries);

let digest = format!("{:x}", md5_hash.finalize());
Some(RuntimeString::new(digest))
}

#[module_main]
fn main(data: &[u8], _meta: Option<&[u8]>) -> Macho {
match parser::MachO::parse(data) {
Expand Down
48 changes: 48 additions & 0 deletions lib/src/modules/macho/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ fn test_macho_module() {
"src/modules/macho/tests/testdata/chess.in.zip",
);

let symbolt_table_test_data = create_binary_from_zipped_ihex(
"src/modules/macho/tests/testdata/8962a76d0aeaee3326cf840de11543c8beebeb768e712bd3b754b5cd3e151356.in.zip",
);

rule_true!(
r#"
import "macho"
Expand Down Expand Up @@ -474,4 +478,48 @@ fn test_macho_module() {
"#,
&tiny_universal_macho_data
);

rule_true!(
r#"
import "macho"
rule macho_test {
condition:
not defined macho.sym_hash()
}
"#,
&[]
);

rule_true!(
r#"
import "macho"
rule macho_test {
condition:
macho.sym_hash() == "fea44765d5601027002d40c278d119aa"
}
"#,
&symbolt_table_test_data
);

rule_false!(
r#"
import "macho"
rule macho_test {
condition:
macho.sym_hash() == "786daad487993f71b1ba40d0f43a9e0f"
}
"#,
&symbolt_table_test_data
);

rule_true!(
r#"
import "macho"
rule macho_test {
condition:
macho.sym_hash() == "a9ccc7c7b8bd33a99dc7ede4e8d771b4"
}
"#,
&tiny_universal_macho_data
);
}

0 comments on commit 260a2c4

Please sign in to comment.