Skip to content

Technical architecture

exav is a Cargo workspace of focused crates rather than one binary, plus two WebAssembly packages built outside the workspace with their own profile. How the scanner works inside is in How scanning works, and how the extractor does in How extraction works.

The CLI (which is also the daemon) drives the scanning engine, exav-core, which also builds its own WASI binary, exav-wasm (feature wasi-bin). Two front ends use only the extractor, exav-unpack: the archive grep and @exav/unpack-wasm. @exav/viewer’s wasm modules use only exav-render.

exav-core hashes images through exav-imagehash (the image-hash feature), which decodes them with exav-render. exav-render reads DWG and DXF with exav-unpack’s drawing parsers (its dwg feature); the scanner draws nothing. exav-update, behind the http-update feature (part of http), sits to the side, feeding fresh signatures out of band.

Every arrow points down: nothing calls anything above it, which is what lets the extraction, decoding and hashing crates be taken on their own. Dashed arrows are optional dependencies, each behind the Cargo feature it is labelled with.

exav crate dependency graph Four front ends sit on top: exav, exav-viewer (the wasm half of @exav/viewer), exav-grep and exav-unpack-wasm. exav depends on exav-core, and on exav-update behind the http-update feature. exav-core also builds exav-wasm, its wasm32-wasip1 binary. exav-core depends on exav-imagehash behind the image-hash feature, on exav-unpack, and on exav-x86 for the bytecode disassembly API. exav-imagehash and exav-viewer depend on exav-render, which depends on exav-unpack behind its dwg feature. exav-grep and exav-unpack-wasm depend on exav-unpack, which depends on exav-pe-emu behind its pe-emu feature, which depends on exav-x86. FRONT ENDS exav exav-viewer exav-grep exav-unpack-wasm exav-update exav-core exav-imagehash exav-render exav-unpack exav-pe-emu exav-x86 malware scanner CLI · daemon · ICAP server file viewer, wasm @exav/viewer grep inside archives extractor, wasm @exav/unpack-wasm signature download typing · patterns · hashes YARA · .cbc VM + exav-wasm (WASI binary) image hashes image decoders DWG · DXF · IFC · STL archives · disk images · documents packed executables packer stub emulator x86 instruction decoder http-update image-hash dwg pe-emu bytecode disasm

Every crate in the graph is #![forbid(unsafe_code)] except exav, whose daemon calls libc to fork its workers, set their limits, handle signals and pass file descriptors between processes. The unsafe that remains is in dependencies (see Dependencies).

Extraction touches hostile bytes first and hardest, so it lives in its own crate with its own budget and panic containment. It also means one piece can be used alone: a build system that needs to look inside archives does not need a virus scanner, and a reverse engineer who wants to unpack a packed executable needs neither.

exav-pe-emu sits below the extractor for the same reason. Running a packer’s stub is the one place where the scanner executes attacker-authored control flow rather than parsing attacker-authored data, so it is its own crate with its own budgets and no way to reach a syscall.

Each crate has its own page, with install instructions, API, and examples: exav-unpack and @exav/unpack-wasm under Archive extraction, @exav/viewer under File viewer, and the rest under Subprojects.