Modules
Modules extend the YARA-X rule language with knowledge that the core engine does not
have on its own. A plain rule matches on the raw bytes of a file; a module understands
structure — the sections of a PE executable, the imports of an ELF binary, the entropy
of a byte range, the current time, and so on. Once a module is imported, its fields and
functions become available inside a rule's condition.
Modules are written in Rust and ship compiled into the engine, so there is nothing to
install. You only need to make a module visible to a rule with the import statement.
import "pe"
rule single_section_executable {
condition:
pe.is_pe and pe.number_of_sections == 1
}
The import statement appears at the top of the file, before any rule. Importing a
module that a rule never uses is harmless. A rule can import as many modules as it needs.
Built-in modules
YARA-X ships the following modules. The set is verified against the official modules documentation.
| Module | Purpose |
|---|---|
pe | Parse Windows Portable Executable (PE) files — sections, imports, exports, headers, signatures. |
elf | Parse ELF executables and shared objects (Linux and other Unix-like systems). |
macho | Parse Mach-O binaries used by macOS and iOS, including fat/universal files. |
dotnet | Inspect .NET assembly metadata (streams, GUIDs, type and method tables). |
dex | Parse Android DEX (Dalvik Executable) files. |
lnk | Parse Windows shortcut (.lnk) files. |
crx | Parse Chrome extension (CRX) packages. |
math | Statistical and numeric helpers — entropy, mean, deviation, min/max, and more. |
hash | Compute MD5, SHA-1, SHA-256, CRC32, and a simple 32-bit checksum over byte ranges or strings. |
string | String helper functions for use inside conditions. |
time | Access the current time, for time-relative conditions. |
console | Print values to standard output while a rule is evaluated, for debugging. |
Module availability can depend on how YARA-X was built. Some modules are gated behind
Cargo feature flags, so a custom build might exclude one or more of them. The modules
listed above are those documented for the standard distribution. Check
yr --help and the
documentation for the build you are using if a module is missing.
Referencing module fields
After importing a module you reference its members with dot notation:
module.field or module.function(args). Fields hold values parsed from the scanned
data; functions compute a value on demand.
Some fields are scalars, others are arrays or dictionaries that you index or iterate
over. The condition below combines a scalar field, an array element, and a function call
from the pe module.
import "pe"
rule example_pe_condition {
meta:
description = "Illustrative example — not a real detection rule"
condition:
pe.is_pe and
pe.number_of_sections > 1 and
pe.sections[0].name == ".text" and
pe.imports("kernel32.dll", "CreateFileW")
}
The rule above is illustrative. It demonstrates syntax rather than detecting any specific malware family.
The pe module
The pe module is the most widely used. A few of its commonly referenced members:
| Member | Kind | Meaning |
|---|---|---|
pe.is_pe | field (bool) | True when the scanned file is a PE. |
pe.number_of_sections | field (int) | Count of sections in the file. |
pe.entry_point | field (int) | Entry point as a file offset. |
pe.machine | field (int) | Target machine type. |
pe.timestamp | field (int) | Build timestamp as a Unix epoch value. |
pe.sections[i].name | array field | Name of the i-th section. |
pe.imports(dll) | function | Number of functions imported from dll. |
pe.imports(dll, func) | function | True when func is imported from dll. |
pe.exports(func) | function | True when func is exported. |
import "pe"
rule control_panel_applet {
condition:
pe.is_pe and pe.exports("CPlApplet")
}
The hash module
The hash module computes cryptographic and non-cryptographic digests. Each function has
two forms: one that operates on a byte range of the scanned data (offset, size), and one
that operates on a literal string.
| Function | Result |
|---|---|
hash.md5(offset, size) / hash.md5(string) | MD5 digest (lowercase hex string). |
hash.sha1(offset, size) / hash.sha1(string) | SHA-1 digest. |
hash.sha256(offset, size) / hash.sha256(string) | SHA-256 digest. |
hash.crc32(offset, size) / hash.crc32(string) | CRC32 checksum (integer). |
hash.checksum32(offset, size) / hash.checksum32(string) | 32-bit sum of all bytes. |
import "hash"
rule known_file_by_md5 {
condition:
hash.md5(0, filesize) == "feba6c919e3797e7778e8f2e85fa033d"
}
filesize is a built-in constant equal to the size of the data being scanned. Pairing it
with an offset of 0 — as in hash.md5(0, filesize) or math.entropy(0, filesize) —
applies a function across the whole file.
The math module
The math module provides statistical helpers, most often used to gauge how "random" a
byte range looks. High entropy frequently indicates compressed or encrypted content.
| Function | Result |
|---|---|
math.entropy(offset, size) | Shannon entropy of the byte range (0–8). |
math.mean(offset, size) | Mean byte value over the range. |
math.deviation(offset, size, mean) | Average deviation from a given mean. |
math.in_range(value, lower, upper) | True when value falls within bounds. |
math.min(a, b) / math.max(a, b) | Smaller / larger of two integers. |
import "math"
rule likely_packed {
condition:
math.entropy(0, filesize) >= 7.0
}
The time module
The time module exposes the current time, letting a rule reason about when it runs
rather than only what it scans. time.now() returns the current time as a Unix
timestamp (seconds since the epoch).
import "pe"
import "time"
rule recently_built_pe {
meta:
description = "Illustrative example — flags PEs built within the last 24 hours"
condition:
pe.is_pe and
(time.now() - pe.timestamp) < 86400
}
This rule is illustrative. Compile timestamps are attacker-controlled and unreliable,
so a real rule would not depend on pe.timestamp alone.
Inspecting module output
Before writing conditions, it helps to see exactly what a module parses out of a given
file. The yr dump command prints a module's structured output for a target so you can
discover the available fields and their values.
yr dump --module pe sample.exe
The output mirrors the fields you reference in conditions — sections, imports, headers, and so on — making it a practical way to confirm field names and inspect real values.