diff --git a/site/content/blog/introducing-yara-x/index.md b/site/content/blog/introducing-yara-x/index.md index 95477af8f..79b3ffece 100644 --- a/site/content/blog/introducing-yara-x/index.md +++ b/site/content/blog/introducing-yara-x/index.md @@ -18,14 +18,14 @@ seo: noindex: false # false (default) or true --- -For over 15 years, YARA has been growing and evolving until it became -an indispensable tool in every malware researcher's toolbox. Throughout this -time YARA has seen numerous updates, with new features added and countless bugs -fixed. But today, I'm excited to announce the biggest change yet: a complete -rewrite. +For over 15 years, [YARA](https://github.com/VirusTotal/yara) has been growing +and evolving until it became an indispensable tool in every malware researcher's +toolbox. Throughout this time YARA has seen numerous updates, with new features +added and countless bugs fixed. But today, I'm excited to announce the biggest +change yet: a full rewrite. -YARA-X is a completely new implementation of YARA, and it has the following -goals: +YARA-X is a completely new implementation of YARA in Rust, and it has the +following goals: * **Better user experience**: The new command-line interface is more modern and colorful, and error reports are now more explicative. More features aimed at diff --git a/site/content/docs/api/_index.md b/site/content/docs/api/_index.md index c90b418a3..d39f21ac1 100644 --- a/site/content/docs/api/_index.md +++ b/site/content/docs/api/_index.md @@ -11,6 +11,8 @@ menu: identifier: "apis" weight: 500 toc: true +sidebar: + collapsed: true seo: title: "" # custom title (optional) description: "" # custom description (recommended) diff --git a/site/content/docs/intro/_index.md b/site/content/docs/intro/_index.md index 4e02059ae..e0f081d0d 100644 --- a/site/content/docs/intro/_index.md +++ b/site/content/docs/intro/_index.md @@ -11,6 +11,8 @@ menu: identifier: "intro" weight: 100 toc: true +sidebar: + collapsed: true seo: title: "" # custom title (optional) description: "" # custom description (recommended) diff --git a/site/content/docs/intro/yara_vs_yara-x.md b/site/content/docs/intro/yara_vs_yara-x.md index 4a88e50ee..6515e40b0 100644 --- a/site/content/docs/intro/yara_vs_yara-x.md +++ b/site/content/docs/intro/yara_vs_yara-x.md @@ -46,11 +46,14 @@ its YARA counterpart: * Colorful output, enhancing readability if the terminal supports it. * More information about the files being scanned. -* Autocompletion support for multiple shells, including bash, zsh, and - powershell, improving usability and efficiency during command entry. +* Autocompletion support for multiple shells, including Bash, Zsh, and + PowerShell, improving usability and efficiency during command entry. * Access to the output of YARA modules in YAML and JSON formats without requiring any YARA rule. This capability transforms YARA-X into a versatile - file dissection tool supporting multiple file formats (PE, ELF, Mach-O, LNK). + file dissection tool supporting multiple file formats, like + [PE](https://en.wikipedia.org/wiki/Portable_Executable), [ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format), + [Mach-O](https://en.wikipedia.org/wiki/Mach-O) + and LNK (Windows link file). ### Higher overall performance diff --git a/site/content/docs/modules/console.md b/site/content/docs/modules/console.md index fe8477c36..388aa9c9b 100644 --- a/site/content/docs/modules/console.md +++ b/site/content/docs/modules/console.md @@ -34,6 +34,8 @@ rule example { } ``` +------- + ## Functions ### log(string) diff --git a/site/content/docs/modules/dotnet.md b/site/content/docs/modules/dotnet.md index 1e291de2b..d6b6c8728 100644 --- a/site/content/docs/modules/dotnet.md +++ b/site/content/docs/modules/dotnet.md @@ -43,6 +43,8 @@ rule BlopStream { } ``` +------- + ## Module structure | Field | Type | diff --git a/site/content/docs/modules/elf.md b/site/content/docs/modules/elf.md index bbbe4bf23..d568516be 100644 --- a/site/content/docs/modules/elf.md +++ b/site/content/docs/modules/elf.md @@ -37,6 +37,8 @@ rule elf_64 { } ``` +------- + ## Functions ### import_md5() @@ -65,6 +67,8 @@ rule FindByTelfhash { } ``` +------- + ## Module structure | Field | Type | diff --git a/site/content/docs/modules/hash.md b/site/content/docs/modules/hash.md index 188a72228..3c777f9df 100644 --- a/site/content/docs/modules/hash.md +++ b/site/content/docs/modules/hash.md @@ -22,6 +22,8 @@ The `hash` module allows you to calculate hashes (MD5, SHA1, SHA256) and checksums from portions of your file and create signatures based on those hashes. +------- + ## Functions {{< callout context="caution" title="Important">}} diff --git a/site/content/docs/modules/lnk.md b/site/content/docs/modules/lnk.md index 793097a42..6fc92d0a0 100644 --- a/site/content/docs/modules/lnk.md +++ b/site/content/docs/modules/lnk.md @@ -21,6 +21,8 @@ seo: The `lnk` module parses Windows Link files (.lnk), and exposes metadata contained in those files to YARA. +------- + ## Module structure | Field | Type | Description | diff --git a/site/content/docs/modules/macho.md b/site/content/docs/modules/macho.md index cd208e126..05688a6d6 100644 --- a/site/content/docs/modules/macho.md +++ b/site/content/docs/modules/macho.md @@ -19,8 +19,10 @@ seo: --- The `macho` module is very similar to the [pe]({{< ref "pe.md" >}}) module, but -for [Match-O](https://en.wikipedia.org/wiki/Mach-O) files. This module exposes -most of the fields present in a Mach-O file header. Let's see some examples: +for [Mach-O](https://en.wikipedia.org/wiki/Mach-O) files. This module exposes +most of the fields present in a Mach-O file header. + +------- ### Module structure diff --git a/site/content/docs/modules/math.md b/site/content/docs/modules/math.md index f933dcdd8..dd74b07d0 100644 --- a/site/content/docs/modules/math.md +++ b/site/content/docs/modules/math.md @@ -21,6 +21,8 @@ seo: The `math` module allows you to calculate certain values from portions of your file and create signatures based on those results. +------- + ## Functions ### entropy(offset, size) diff --git a/site/content/docs/modules/pe.md b/site/content/docs/modules/pe.md index 0495713f4..c63099fa5 100644 --- a/site/content/docs/modules/pe.md +++ b/site/content/docs/modules/pe.md @@ -48,8 +48,98 @@ rule is_pe { } ``` +------- + ## Functions +### exports(fn_name) + +Returns true if the PE exports a function with the given name, or false +otherwise. + +### exports(fn_regex) + +Returns true if the PE exports a function whose name matches the given regular +expression, or false otherwise. + +### exports(ordinal) + +Returns true if the PE exports a function with the given ordinal, or false if +otherwise. + +### exports_index(fn_name) + +Returns the index into the `export_details` array for the first exported +function that matches the given name. The result is `undefined` if no +function with such a name exists. + +### exports_index(fn_regex) + +Returns the index into the `export_details` array for the first exported +function that matches the given regular expression. The result is `undefined` if +none of the functions matches. + +### exports_index(ordinal) + +Returns the index into the `export_details` array for the first exported +function that has the given ordinal number. The result is `undefined` if no +function exists with such an ordinal exists. + +### imports(dll_name) + +Returns the number of functions that the PE imports from the given DLL. The +DLL name is case-insensitive. + +### imports(dll_name, fn_name) + +Returns true if the PE imports the given function from the given DLL. The DLL +name is case-insensitive, but the function name is case-sensitive. + +### imports(dll_name, ordinal) + +Returns true if the PE imports the given function by ordinal from the given DLL. +The DLL name is case-insensitive. + +### imports(dll_regex, fn_regex) + +Returns the number of functions imported by the PE where the DLL name matches +`dll_regexp` and the function name matches `fn_regexp`. Both arguments are +case-sensitive, unless you use the `/i` modifier in the regexp. + +###### Example + +``` +import "pe" + +rule ProcessMemory { + condition: + pe.imports(/kernel32.dll/i, /(Read|Write)ProcessMemory/) > 0 +} +``` + +### imports(type, dll_name, fn_name) + +Returns true if the PE imports `fn_name` from `dll_name`. The DLL +name is case-insensitive. `type` allows to specify the kind of imports should be +taken into account, the allowed values are: + +| | | +|----------------------|-----------------------------------| +| `pe.IMPORT_STANDARD` | Standard imports only | +| `pe.IMPORT_DELAYED` | Delayed imports only | +| `pe.IMPORT_ANY` | Both standard and delayed imports | + +###### Example + +``` +import "pe" + +rule ProcessMemory { + condition: + pe.imports(pe.IMPORT_DELAYED, "kernel32.dll", "WriteProcessMemory") +} +``` + ### is_32bit() Returns true if the file is a 32-bit PE. @@ -106,6 +196,30 @@ The returned hash string is always in lowercase. {{< /callout >}} +### rich_signature.version(version, [toolid]) + +The PE rich signature contains information about the tools involved in the +creation of the PE file. This function returns the number of tools that +matches the given version and toolid, where toolid is optional. + +###### Example + +``` +import "pe" + +rule WrongChecksum { + condition: + pe.rich_signature.version(24215, 261) == 61 +} +``` + +### rich_signature.toolid(toolid, [version]) + +This function is similar to `rich_signature.version`, but the toolid argument +is required while version is optional. + +------ + ## Module structure | Field | Type | Description | diff --git a/site/content/docs/modules/string.md b/site/content/docs/modules/string.md index 39dbf6518..46736428a 100644 --- a/site/content/docs/modules/string.md +++ b/site/content/docs/modules/string.md @@ -21,6 +21,8 @@ seo: The `string` module implements string utility functions. +------- + ## Functions ### to_int(string) diff --git a/site/content/docs/modules/time.md b/site/content/docs/modules/time.md index 9afe4dbac..c3bf0527a 100644 --- a/site/content/docs/modules/time.md +++ b/site/content/docs/modules/time.md @@ -20,6 +20,8 @@ seo: The `time` module implements time utility functions. +------- + ## Functions ### now() diff --git a/site/content/docs/writing_rules/differences.md b/site/content/docs/writing_rules/differences.md index 0a09e34c6..62f7adc4a 100644 --- a/site/content/docs/writing_rules/differences.md +++ b/site/content/docs/writing_rules/differences.md @@ -9,7 +9,7 @@ menu: docs: parent: "" identifier: "differences" -weight: 280 +weight: 290 toc: true seo: title: "" # custom title (optional) diff --git a/site/content/docs/writing_rules/syntax.md b/site/content/docs/writing_rules/syntax.md index b20ee343f..1a6d5af3f 100644 --- a/site/content/docs/writing_rules/syntax.md +++ b/site/content/docs/writing_rules/syntax.md @@ -30,13 +30,13 @@ rule example { ``` Each rule in YARA starts with the keyword `rule` followed by a rule identifier. -Rules are generally composed of two sections: pattern definitions and condition. -The pattern definition section is optional, and it can be omitted if the rule -doesn't rely on any patterns (as in the first example), but the condition -section is always required. The pattern definition section is where the patterns -that will be part of the rule are defined. Patterns can be defined as plain -text, raw bytes, or regular expressions, as shown in the following, more -realistic, example: +Rules are generally composed of two sections: patterns (a.k.a. strings) +and condition. The pattern definition section is optional, and it +can be omitted if the rule doesn't rely on any patterns (as in the first +example), but the condition section is always required. The pattern definition +section is where the patterns that will be part of the rule are defined. +Patterns can be defined as plain text, raw bytes, or regular expressions, as +shown in the following, more realistic, example: ```yara rule ExampleRule { @@ -81,7 +81,7 @@ rule MetadataExample { ``` As shown in the example, metadata identifiers are followed by an equal sign and -the value assigned to them. Values can be strings (valid UTF8 only), integers, +the value assigned to them. Values can be strings (valid UTF-8 only), integers, or one of the boolean values `true` or `false`. Note that identifier/value pairs defined in the metadata section cannot be used diff --git a/site/content/docs/writing_rules/undefined_values.md b/site/content/docs/writing_rules/undefined_values.md new file mode 100644 index 000000000..9859641b4 --- /dev/null +++ b/site/content/docs/writing_rules/undefined_values.md @@ -0,0 +1,73 @@ +--- +title: "Undefined values" +description: "Explains what are undefined values in YARA" +summary: "" +date: 2023-09-07T16:13:18+02:00 +lastmod: 2023-09-07T16:13:18+02:00 +draft: false +menu: + docs: + parent: "" + identifier: "undefined" +weight: 280 +toc: true +seo: + title: "" # custom title (optional) + description: "" # custom description (recommended) + canonical: "" # custom canonical URL (optional) + noindex: false # false (default) or true +--- + +Modules often leave variables in an undefined state, for example when the +variable doesn't make sense in the current context (think of `pe.entry_point` +while scanning a non-PE file). YARA handles undefined values in a way that +allows the rule to keep its meaningfulness. Take a look at this rule: + +```yara +import "pe" + +rule Test { + strings: + $a = "some string" + condition: + $a and pe.entry_point == 0x1000 +} +``` + +If the scanned file isn't a PE file, this rule won't match even if "some string" +is present because both conditions (the string's presence and the correct entry +point) must be met. However, consider the `or` case: + +``` +$a or pe.entry_point == 0x1000 +``` + +You would expect the rule to match if the file contains the string, even if it +isn't a PE file. That's exactly how YARA behaves. The logic is as follows: + +If the expression in the condition is `undefined`, it would be translated +to `false` and the rule won't match. + +Boolean operators `and` and `or` will treat `undefined` operands as `false`, +Which means that: + +* `undefined` and `true` is `false` +* `undefined` and `false` is `false` +* `undefined` or `true` is `true` +* `undefined` or `false` is `false` + +All the remaining operators, including the `not` operator, return `undefined` if +any of their operands is `undefined`. + +In the expression above, `pe.entry_point == 0x1000` will be undefined for non-PE +files, because `pe.entry_point` is undefined for those files. This implies that +`$a or pe.entry_point == 0x1000` will be `true` if and only if `$a` is `true`. + +If the condition was `pe.entry_point == 0x1000` alone, it evaluates to `false` +for non-PE files, and so will do `pe.entry_point != 0x1000` and `not +pe.entry_point == 0x1000`, as none of these expressions make sense for non-PE +files. + +To check if some expression is defined use unary operator `defined`. Example: + +`defined pe.entry_point` \ No newline at end of file