Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,49 @@ jobs:
"--no-default-features --features=object,authenticode,authenticode-verify",
"--all-features"
]

other-archs:
name: Test other architectures
runs-on: ubuntu-22.04
env:
CROSS_VERSION: v0.2.5
steps:
- uses: actions/checkout@v3

- name: Install and configure Cross
run: |
# Copied from rust-lang/regex CI:
# <https://github.com/rust-lang/regex/blob/329c6a32/.github/workflows/ci.yml>
dir="$RUNNER_TEMP/cross-download"
mkdir "$dir"
echo "$dir" >> $GITHUB_PATH
cd "$dir"
curl -LO "https://github.com/cross-rs/cross/releases/download/$CROSS_VERSION/cross-x86_64-unknown-linux-musl.tar.gz"
tar xf cross-x86_64-unknown-linux-musl.tar.gz
echo "CARGO=cross" >> $GITHUB_ENV
echo "TARGET=--target ${{ matrix.target }}" >> $GITHUB_ENV

- name: Build test helpers
run: |
cd boreal-test-helpers
${{ env.CARGO }} build $TARGET

- name: Run tests
env:
YARA_CRYPTO_LIB: openssl
run: ${{ env.CARGO }} test $TARGET

- name: Run tests with authenticode
env:
YARA_CRYPTO_LIB: openssl
run: ${{ env.CARGO }} test --features authenticode-verify $TARGET

strategy:
fail-fast: false
matrix:
build: [s390x, aarch64]
include:
- build: s390x
target: s390x-unknown-linux-gnu
- build: aarch64
target: aarch64-unknown-linux-gnu
17 changes: 17 additions & 0 deletions Cross.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[target.s390x-unknown-linux-gnu]
image = "ghcr.io/cross-rs/s390x-unknown-linux-gnu:main"
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update",
"apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH",
"apt-get install --assume-yes --no-install-recommends libclang-10-dev clang-10"
]

[target.aarch64-unknown-linux-gnu]
image = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu:main"
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH",
"apt-get update",
"apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH",
"apt-get install --assume-yes --no-install-recommends libclang-10-dev clang-10"
]
94 changes: 49 additions & 45 deletions boreal/tests/it/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -859,53 +859,10 @@ pub fn compare_module_values_on_mem<M: Module>(
// Enrich value using the static values, so that it can be compared with yara's
enrich_with_static_values(&mut boreal_value, module.get_static_values());

let mut yara_value = None;
let yara_cb = |msg| {
if let yara::CallbackMsg::ModuleImported(obj) = msg {
let mut yara_value = convert_yara_obj_to_module_value(obj);

// This is a hack to remove the "rich_signature" field from the pe module
// when the file is not a PE. The PE module on yara has a lot of idiosyncracies,
// but two of them conflates here: it is the only module that has values when it
// does not parse anything (the is_pe field is set, either to 1 or 0), and it
// always sets the rich_signature field even if it does not contain anything
// (because it contains two functions).
// This is very annoying to handle when comparing module values, so just remove
// this dummy value when the file is not a pe, it serves no purpose.
if let ModuleValue::Object(map) = &mut yara_value {
if matches!(map.get("is_pe"), Some(ModuleValue::Integer(0))) {
map.remove("rich_signature");
}
}

let mut diffs = Vec::new();
compare_module_values(&boreal_value, yara_value, module.get_name(), &mut diffs);

// Remove ignored diffs from the reported ones.
for path in ignored_diffs {
match diffs.iter().position(|d| &d.path == path) {
Some(pos) => {
diffs.remove(pos);
}
None => {
panic!("ignored diff on path {path} but there is no diff on this path",);
}
}
}

if !diffs.is_empty() {
panic!(
"found {} differences for module {} on {}{}: {:#?}",
diffs.len(),
module.get_name(),
mem_name,
if process_memory {
" with process memory flag"
} else {
""
},
diffs
);
}
yara_value = Some(convert_yara_obj_to_module_value(obj));
}
yara::CallbackReturn::Continue
};
Expand All @@ -923,6 +880,53 @@ pub fn compare_module_values_on_mem<M: Module>(
} else {
yara_scanner.scan_mem_callback(mem, yara_cb).unwrap();
}

let Some(mut yara_value) = yara_value else {
panic!("Missed module imported yara callback");
};
// This is a hack to remove the "rich_signature" field from the pe module
// when the file is not a PE. The PE module on yara has a lot of idiosyncracies,
// but two of them conflates here: it is the only module that has values when it
// does not parse anything (the is_pe field is set, either to 1 or 0), and it
// always sets the rich_signature field even if it does not contain anything
// (because it contains two functions).
// This is very annoying to handle when comparing module values, so just remove
// this dummy value when the file is not a pe, it serves no purpose.
if let ModuleValue::Object(map) = &mut yara_value {
if matches!(map.get("is_pe"), Some(ModuleValue::Integer(0))) {
map.remove("rich_signature");
}
}

let mut diffs = Vec::new();
compare_module_values(&boreal_value, yara_value, module.get_name(), &mut diffs);

// Remove ignored diffs from the reported ones.
for path in ignored_diffs {
match diffs.iter().position(|d| &d.path == path) {
Some(pos) => {
diffs.remove(pos);
}
None => {
panic!("ignored diff on path {path} but there is no diff on this path",);
}
}
}

if !diffs.is_empty() {
panic!(
"found {} differences for module {} on {}{}: {:#?}",
diffs.len(),
module.get_name(),
mem_name,
if process_memory {
" with process memory flag"
} else {
""
},
diffs
);
}
}

fn enrich_with_static_values(
Expand Down