diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7862dec9..ba169312 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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: + # + 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 diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 00000000..98c43d03 --- /dev/null +++ b/Cross.toml @@ -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" +] diff --git a/boreal/tests/it/utils.rs b/boreal/tests/it/utils.rs index c79a6f25..9c197d75 100644 --- a/boreal/tests/it/utils.rs +++ b/boreal/tests/it/utils.rs @@ -859,53 +859,10 @@ pub fn compare_module_values_on_mem( // 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 }; @@ -923,6 +880,53 @@ pub fn compare_module_values_on_mem( } 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(