YARA modules: pe, elf, dotnet, math, hash and more
Use YARA modules to query parsed file formats: pe imports and sections, elf, macho, dotnet, lnk, math entropy, hash, console and string, with YARA-X notes.
Modules extend the condition language with parsers and helper functions. Instead of hand-computing offsets in a PE header, you can ask pe.number_of_sections or check whether a DLL imports VirtualAllocEx. This guide covers the modules you will meet most often in public rules and the ones available in the browser tools on this site.
Importing a module
Declare modules at the top of the file with import. A module is parsed only for files it recognises: on a text file, pe.is_pe is simply false and most pe fields are undefined, which makes expressions that use them false as well.
import "pe"
import "math"
rule Module_Import_Example
{
condition:
pe.is_pe and math.entropy(0, filesize) > 7.2
}
The WebAssembly build of YARA-X used by the scanner and editor ships pe, elf, macho, dotnet, lnk, math, hash, time, console, string, dex, crx, cuckoo and vt. The magic module is not available there.
pe — Windows executables
The most used module. Frequent fields and functions:
| Expression | Use |
|---|---|
pe.is_pe, pe.is_dll(), pe.is_64bit() | File kind |
pe.number_of_sections, pe.sections[i].name | Section layout (packers, unusual names) |
pe.imports("kernel32.dll", "VirtualAllocEx") | Imported function |
pe.exports("ServiceMain") | Exported function |
pe.imphash() | Import hash, lowercase hex string |
pe.entry_point | File offset of the entry point |
pe.timestamp | Compile timestamp from the header |
pe.number_of_signatures, pe.signatures[i].issuer | Authenticode signatures |
import "pe"
rule PE_Injection_Imports
{
meta:
= "Small PE importing the classic remote-injection API trio"
condition:
uint16(0) == 0x5A4D and filesize < 2MB and
pe.imports("kernel32.dll", "VirtualAllocEx") and
pe.imports("kernel32.dll", "WriteProcessMemory") and
pe.imports("kernel32.dll", "CreateRemoteThread")
}
rule PE_Odd_Section_Name
{
condition:
uint16(0) == 0x5A4D and
for any s in pe.sections : ( s.name == ".detourd" or s.name == "UPX0" )
}
Import matching is case-insensitive for the DLL name. Imphash values are compared as lowercase strings: pe.imphash() == "…".
elf and macho
elf exposes the header, sections, segments and symbols of Linux and Unix executables; macho does the same for macOS binaries, including fat (universal) files.
import "elf"
rule ELF_Small_x64_Executable
{
condition:
uint32(0) == 0x464C457F and
elf.type == elf.ET_EXEC and
elf.machine == elf.EM_X86_64 and
filesize < 1MB
}
dotnet
For .NET assemblies: assembly name and version, GUIDs, resources, streams, type references. The module GUID (dotnet.guids) and the assembly name are often stable across builds of the same tool.
import "dotnet"
rule DotNet_Assembly_Name
{
condition:
dotnet.is_dotnet and dotnet.assembly.name == "SharpExample"
}
lnk
Parses Windows shortcut files: target path, arguments, working directory, icon location, machine identifier. Useful for phishing shortcuts that launch powershell or mshta.
import "lnk"
rule LNK_Launches_Mshta
{
condition:
lnk.is_lnk and lnk.local_base_path contains "mshta"
}
math and hash
math.entropy(offset, size) returns the Shannon entropy of a range (0 to 8): values above ~7.2 suggest compressed or encrypted data. hash.md5/sha1/sha256(offset, size) return lowercase hex strings; hash.crc32 returns an integer.
import "math"
import "hash"
rule Encrypted_Overlay_Or_Known_Blob
{
condition:
filesize < 5MB and (
math.entropy(filesize - 4096, 4096) > 7.5 or
hash.sha256(0, 1024) == "0000000000000000000000000000000000000000000000000000000000000000"
)
}
Hashing or measuring entropy over the whole file (0, filesize) is expensive on large files. Guard these calls with filesize and cheap checks placed first, as explained in the performance guide.
console, string and time
console.log("text", value)prints values when the rule is evaluated — a debugging aid for complex conditions. Remove it before sharing.string.to_int("123")andstring.length(…)help with values extracted by other modules.time.now()returns the current Unix time, e.g. to compare withpe.timestamp.
import "pe"
import "time"
rule PE_Timestamp_In_Future
{
condition:
pe.is_pe and pe.timestamp > time.now()
}
dex, crx, cuckoo and vt
dex parses Android DEX bytecode files, crx Chrome extension packages. cuckoo reads a sandbox behaviour report passed alongside the file, and vt exposes VirusTotal metadata in Livehunt; both need external data and are only meaningful in the platforms that provide it (see YARA on VirusTotal).
YARA-X differences
Module names and most field names are the same as in YARA 4.x, so the majority of rules port without changes. A few fields were renamed or reorganised, and YARA-X reports an unknown field as a compile error instead of silently evaluating to undefined. When a rule fails, run yr dump -m pe sample.exe to see the exact structure YARA-X produces, and check the YARA-X vs YARA guide. The rule pages in the library show whether each rule compiles with YARA-X.
Choosing between a module and raw bytes
A module call is expressive and robust to layout changes, but parsing costs time. For simple checks — "is this a PE?" — uint16(0) == 0x5A4D is both faster and sufficient. Use modules for what bytes cannot express easily: imports, signatures, resources, section tables. The linter points out rules that call pe or elf without a magic-byte guard first.
FAQ
- Do I need to import a module to use it?
- Yes. Add import "pe" (or the module you need) at the top of the file; referencing pe.something without the import is a compile error.
- How can I see what a module extracts from a file?
- With the YARA-X command line, yr dump file.exe prints the output of every applicable module; yr dump -m pe file.exe limits it to the pe module.
- Is the magic module available in YARA-X?
- It depends on the build. It relies on libmagic and is missing from some builds, including the WebAssembly build used by the tools on this site.