From f9597a12ba1206d9be0830b5343a4a5785612e26 Mon Sep 17 00:00:00 2001 From: "Victor M. Alvarez" Date: Tue, 7 Jul 2026 13:16:30 +0200 Subject: [PATCH 1/4] perf: use `FxHashMap` instead of `HashMap`. Also includes other minor optimizations. --- lib/src/modules/crx/parser.rs | 2 +- lib/src/modules/vba/mod.rs | 11 +++++------ lib/src/modules/vba/parser.rs | 2 +- lib/src/re/thompson/compiler.rs | 6 +++--- lib/src/scanner/mod.rs | 3 ++- lib/src/symbols/mod.rs | 17 ++++++++++++----- 6 files changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/src/modules/crx/parser.rs b/lib/src/modules/crx/parser.rs index d695f06c1..9ac6ee9ff 100644 --- a/lib/src/modules/crx/parser.rs +++ b/lib/src/modules/crx/parser.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use rustc_hash::FxHashMap as HashMap; use std::fmt::Write; use std::io::{Cursor, Read, Seek}; diff --git a/lib/src/modules/vba/mod.rs b/lib/src/modules/vba/mod.rs index d4993fdfc..5a0e11851 100644 --- a/lib/src/modules/vba/mod.rs +++ b/lib/src/modules/vba/mod.rs @@ -6,7 +6,7 @@ https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-ovba/575462ba */ use crate::modules::vba::parser::decompress_stream; -use std::collections::HashMap; +use rustc_hash::FxHashMap as HashMap; use crate::mods::prelude::*; use crate::modules::olecf::parser::OLECFParser; @@ -41,11 +41,11 @@ impl<'a> VbaExtractor<'a> { let stream_names = ole_parser.get_stream_names()?; let mut vba_dir = None; - let mut modules = HashMap::new(); + let mut modules = HashMap::default(); // First process the dir stream if let Some(dir_name) = - stream_names.iter().find(|n| n.to_lowercase().trim() == "dir") + stream_names.iter().find(|n| n.trim().eq_ignore_ascii_case("dir")) && let Ok(data) = Self::read_stream_data(&ole_parser, dir_name) { vba_dir = Some(data); @@ -53,12 +53,11 @@ impl<'a> VbaExtractor<'a> { // Then process other streams for name in &stream_names { - let lowercase_name = name.to_lowercase(); - - if lowercase_name != "dir" + if !name.trim().eq_ignore_ascii_case("dir") && let Ok(data) = Self::read_stream_data(&ole_parser, name) && !data.is_empty() { + let lowercase_name = name.to_lowercase(); modules.insert(parser::normalize_name(&lowercase_name), data); } } diff --git a/lib/src/modules/vba/parser.rs b/lib/src/modules/vba/parser.rs index 8062e03bb..0abe3444f 100644 --- a/lib/src/modules/vba/parser.rs +++ b/lib/src/modules/vba/parser.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use rustc_hash::FxHashMap as HashMap; use nom::combinator::opt; use nom::multi::length_data; diff --git a/lib/src/re/thompson/compiler.rs b/lib/src/re/thompson/compiler.rs index b8957bb79..a1127e032 100644 --- a/lib/src/re/thompson/compiler.rs +++ b/lib/src/re/thompson/compiler.rs @@ -7,7 +7,7 @@ matches the regexp left-to-right, and another one that matches right-to-left. */ use itertools::Itertools; -use std::collections::HashMap; +use rustc_hash::FxHashMap as HashMap; use std::collections::hash_map::Entry; use std::fmt::{Display, Formatter}; use std::io::{Cursor, Read, Seek, SeekFrom, Write}; @@ -322,7 +322,7 @@ impl Compiler { // All chunks in `last_n_chucks` will be appended to the backward code // in reverse order. The offset where each chunk resides in the backward // code is stored in the hash map. - let mut chunk_locations = HashMap::new(); + let mut chunk_locations = HashMap::default(); for (location, chunk) in zip(locations.iter_mut(), last_n_chunks.iter()).rev() @@ -1975,7 +1975,7 @@ fn optimize_seq(mut seq: Seq) -> Option { // literal. For instance, if the sequence contains literals `01 02 03` and // `01 02 04`, the key `01 02` will contain a bitmap where bits 3 and 4 // are set, while the rest of the bits are unset. - let mut map = HashMap::new(); + let mut map = HashMap::default(); for lit in literals { // `prefix` contains all bytes in the literal except the last one. diff --git a/lib/src/scanner/mod.rs b/lib/src/scanner/mod.rs index f8cde64a5..ea095c633 100644 --- a/lib/src/scanner/mod.rs +++ b/lib/src/scanner/mod.rs @@ -2,7 +2,8 @@ The scanner takes the rules produces by the compiler and scans data with them. */ -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; +use rustc_hash::FxHashMap as HashMap; use std::fmt::{Debug, Formatter}; use std::fs; use std::io::Read; diff --git a/lib/src/symbols/mod.rs b/lib/src/symbols/mod.rs index 6fddb9080..57c457abe 100644 --- a/lib/src/symbols/mod.rs +++ b/lib/src/symbols/mod.rs @@ -1,8 +1,9 @@ use std::cell::RefCell; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::VecDeque; use std::hash::{Hash, Hasher}; use std::rc::Rc; use std::{mem, ptr}; +use rustc_hash::{FxHashMap, FxHashSet}; #[cfg(test)] use bstr::BString; @@ -192,14 +193,17 @@ impl SymbolLookup for Option { /// object that also implements the [`SymbolLookup`] trait, possibly another /// [`SymbolTable`]. pub(crate) struct SymbolTable { - map: HashMap, - used: RefCell>, + map: FxHashMap, + used: RefCell>, } impl SymbolTable { /// Creates a new symbol table. pub fn new() -> Self { - Self { map: HashMap::new(), used: RefCell::new(HashSet::new()) } + Self { + map: FxHashMap::default(), + used: RefCell::new(FxHashSet::default()), + } } /// Inserts a new symbol into the symbol table. @@ -244,7 +248,10 @@ impl Default for SymbolTable { impl SymbolLookup for &SymbolTable { fn lookup(&self, ident: &str) -> Option { if let Some(symbol) = self.map.get(ident) { - self.used.borrow_mut().insert(ident.to_string()); + let mut used = self.used.borrow_mut(); + if !used.contains(ident) { + used.insert(ident.to_string()); + } Some(symbol.clone()) } else { None From 976d0ca5d80f000e8f30c78edf268c67161ebd4d Mon Sep 17 00:00:00 2001 From: "Victor M. Alvarez" Date: Tue, 7 Jul 2026 13:18:29 +0200 Subject: [PATCH 2/4] perf: optimize ordinal-to-name lookups and string conversion Replace `OnceLock` with a direct `match` statement for `wsock32_ord_to_name`. This eliminates the overhead of dynamic allocation, hashing, and `OnceLock` initialization, improving performance for frequent ordinal lookups. Additionally, avoid an unnecessary `Vec` allocation when converting a byte slice (`&[u8]`) to a UTF-8 string (`String`) during import parsing. --- lib/src/modules/pe/parser.rs | 250 +++++++++++++++++------------------ 1 file changed, 123 insertions(+), 127 deletions(-) diff --git a/lib/src/modules/pe/parser.rs b/lib/src/modules/pe/parser.rs index 5f6604ab5..d858ab649 100644 --- a/lib/src/modules/pe/parser.rs +++ b/lib/src/modules/pe/parser.rs @@ -1929,7 +1929,9 @@ impl<'a> PE<'a> { if let Ok(rva) = TryInto::::try_into(thunk) { func.name = self .parse_at_rva(rva, Self::parse_import_by_name) - .and_then(|s| String::from_utf8(s.to_vec()).ok()) + .and_then(|s| { + from_utf8(s).ok().map(|s| s.to_string()) + }) } } @@ -3277,130 +3279,124 @@ fn oleaut32_ord_to_name(ordinal: u16) -> Option<&'static str> { /// Convert ordinal number to function name for wsock32.dll and ws2_32.dll. fn wsock32_ord_to_name(ordinal: u16) -> Option<&'static str> { - static WSOCK32_ORD_TO_NAME: OnceLock> = - OnceLock::new(); - - let m = WSOCK32_ORD_TO_NAME.get_or_init(|| { - let mut m = HashMap::new(); - m.insert(1, "accept"); - m.insert(2, "bind"); - m.insert(3, "closesocket"); - m.insert(4, "connect"); - m.insert(5, "getpeername"); - m.insert(6, "getsockname"); - m.insert(7, "getsockopt"); - m.insert(8, "htonl"); - m.insert(9, "htons"); - m.insert(10, "ioctlsocket"); - m.insert(11, "inet_addr"); - m.insert(12, "inet_ntoa"); - m.insert(13, "listen"); - m.insert(14, "ntohl"); - m.insert(15, "ntohs"); - m.insert(16, "recv"); - m.insert(17, "recvfrom"); - m.insert(18, "select"); - m.insert(19, "send"); - m.insert(20, "sendto"); - m.insert(21, "setsockopt"); - m.insert(22, "shutdown"); - m.insert(23, "socket"); - m.insert(24, "GetAddrInfoW"); - m.insert(25, "GetNameInfoW"); - m.insert(26, "WSApSetPostRoutine"); - m.insert(27, "FreeAddrInfoW"); - m.insert(28, "WPUCompleteOverlappedRequest"); - m.insert(29, "WSAAccept"); - m.insert(30, "WSAAddressToStringA"); - m.insert(31, "WSAAddressToStringW"); - m.insert(32, "WSACloseEvent"); - m.insert(33, "WSAConnect"); - m.insert(34, "WSACreateEvent"); - m.insert(35, "WSADuplicateSocketA"); - m.insert(36, "WSADuplicateSocketW"); - m.insert(37, "WSAEnumNameSpaceProvidersA"); - m.insert(38, "WSAEnumNameSpaceProvidersW"); - m.insert(39, "WSAEnumNetworkEvents"); - m.insert(40, "WSAEnumProtocolsA"); - m.insert(41, "WSAEnumProtocolsW"); - m.insert(42, "WSAEventSelect"); - m.insert(43, "WSAGetOverlappedResult"); - m.insert(44, "WSAGetQOSByName"); - m.insert(45, "WSAGetServiceClassInfoA"); - m.insert(46, "WSAGetServiceClassInfoW"); - m.insert(47, "WSAGetServiceClassNameByClassIdA"); - m.insert(48, "WSAGetServiceClassNameByClassIdW"); - m.insert(49, "WSAHtonl"); - m.insert(50, "WSAHtons"); - m.insert(51, "gethostbyaddr"); - m.insert(52, "gethostbyname"); - m.insert(53, "getprotobyname"); - m.insert(54, "getprotobynumber"); - m.insert(55, "getservbyname"); - m.insert(56, "getservbyport"); - m.insert(57, "gethostname"); - m.insert(58, "WSAInstallServiceClassA"); - m.insert(59, "WSAInstallServiceClassW"); - m.insert(60, "WSAIoctl"); - m.insert(61, "WSAJoinLeaf"); - m.insert(62, "WSALookupServiceBeginA"); - m.insert(63, "WSALookupServiceBeginW"); - m.insert(64, "WSALookupServiceEnd"); - m.insert(65, "WSALookupServiceNextA"); - m.insert(66, "WSALookupServiceNextW"); - m.insert(67, "WSANSPIoctl"); - m.insert(68, "WSANtohl"); - m.insert(69, "WSANtohs"); - m.insert(70, "WSAProviderConfigChange"); - m.insert(71, "WSARecv"); - m.insert(72, "WSARecvDisconnect"); - m.insert(73, "WSARecvFrom"); - m.insert(74, "WSARemoveServiceClass"); - m.insert(75, "WSAResetEvent"); - m.insert(76, "WSASend"); - m.insert(77, "WSASendDisconnect"); - m.insert(78, "WSASendTo"); - m.insert(79, "WSASetEvent"); - m.insert(80, "WSASetServiceA"); - m.insert(81, "WSASetServiceW"); - m.insert(82, "WSASocketA"); - m.insert(83, "WSASocketW"); - m.insert(84, "WSAStringToAddressA"); - m.insert(85, "WSAStringToAddressW"); - m.insert(86, "WSAWaitForMultipleEvents"); - m.insert(87, "WSCDeinstallProvider"); - m.insert(88, "WSCEnableNSProvider"); - m.insert(89, "WSCEnumProtocols"); - m.insert(90, "WSCGetProviderPath"); - m.insert(91, "WSCInstallNameSpace"); - m.insert(92, "WSCInstallProvider"); - m.insert(93, "WSCUnInstallNameSpace"); - m.insert(94, "WSCUpdateProvider"); - m.insert(95, "WSCWriteNameSpaceOrder"); - m.insert(96, "WSCWriteProviderOrder"); - m.insert(97, "freeaddrinfo"); - m.insert(98, "getaddrinfo"); - m.insert(99, "getnameinfo"); - m.insert(101, "WSAAsyncSelect"); - m.insert(102, "WSAAsyncGetHostByAddr"); - m.insert(103, "WSAAsyncGetHostByName"); - m.insert(104, "WSAAsyncGetProtoByNumber"); - m.insert(105, "WSAAsyncGetProtoByName"); - m.insert(106, "WSAAsyncGetServByPort"); - m.insert(107, "WSAAsyncGetServByName"); - m.insert(108, "WSACancelAsyncRequest"); - m.insert(109, "WSASetBlockingHook"); - m.insert(110, "WSAUnhookBlockingHook"); - m.insert(111, "WSAGetLastError"); - m.insert(112, "WSASetLastError"); - m.insert(113, "WSACancelBlockingCall"); - m.insert(114, "WSAIsBlocking"); - m.insert(115, "WSAStartup"); - m.insert(116, "WSACleanup"); - m.insert(151, "__WSAFDIsSet"); - m.insert(500, "WEP"); - m - }); - - m.get(&ordinal).copied() + match ordinal { + 1 => Some("accept"), + 2 => Some("bind"), + 3 => Some("closesocket"), + 4 => Some("connect"), + 5 => Some("getpeername"), + 6 => Some("getsockname"), + 7 => Some("getsockopt"), + 8 => Some("htonl"), + 9 => Some("htons"), + 10 => Some("ioctlsocket"), + 11 => Some("inet_addr"), + 12 => Some("inet_ntoa"), + 13 => Some("listen"), + 14 => Some("ntohl"), + 15 => Some("ntohs"), + 16 => Some("recv"), + 17 => Some("recvfrom"), + 18 => Some("select"), + 19 => Some("send"), + 20 => Some("sendto"), + 21 => Some("setsockopt"), + 22 => Some("shutdown"), + 23 => Some("socket"), + 24 => Some("GetAddrInfoW"), + 25 => Some("GetNameInfoW"), + 26 => Some("WSApSetPostRoutine"), + 27 => Some("FreeAddrInfoW"), + 28 => Some("WPUCompleteOverlappedRequest"), + 29 => Some("WSAAccept"), + 30 => Some("WSAAddressToStringA"), + 31 => Some("WSAAddressToStringW"), + 32 => Some("WSACloseEvent"), + 33 => Some("WSAConnect"), + 34 => Some("WSACreateEvent"), + 35 => Some("WSADuplicateSocketA"), + 36 => Some("WSADuplicateSocketW"), + 37 => Some("WSAEnumNameSpaceProvidersA"), + 38 => Some("WSAEnumNameSpaceProvidersW"), + 39 => Some("WSAEnumNetworkEvents"), + 40 => Some("WSAEnumProtocolsA"), + 41 => Some("WSAEnumProtocolsW"), + 42 => Some("WSAEventSelect"), + 43 => Some("WSAGetOverlappedResult"), + 44 => Some("WSAGetQOSByName"), + 45 => Some("WSAGetServiceClassInfoA"), + 46 => Some("WSAGetServiceClassInfoW"), + 47 => Some("WSAGetServiceClassNameByClassIdA"), + 48 => Some("WSAGetServiceClassNameByClassIdW"), + 49 => Some("WSAHtonl"), + 50 => Some("WSAHtons"), + 51 => Some("gethostbyaddr"), + 52 => Some("gethostbyname"), + 53 => Some("getprotobyname"), + 54 => Some("getprotobynumber"), + 55 => Some("getservbyname"), + 56 => Some("getservbyport"), + 57 => Some("gethostname"), + 58 => Some("WSAInstallServiceClassA"), + 59 => Some("WSAInstallServiceClassW"), + 60 => Some("WSAIoctl"), + 61 => Some("WSAJoinLeaf"), + 62 => Some("WSALookupServiceBeginA"), + 63 => Some("WSALookupServiceBeginW"), + 64 => Some("WSALookupServiceEnd"), + 65 => Some("WSALookupServiceNextA"), + 66 => Some("WSALookupServiceNextW"), + 67 => Some("WSANSPIoctl"), + 68 => Some("WSANtohl"), + 69 => Some("WSANtohs"), + 70 => Some("WSAProviderConfigChange"), + 71 => Some("WSARecv"), + 72 => Some("WSARecvDisconnect"), + 73 => Some("WSARecvFrom"), + 74 => Some("WSARemoveServiceClass"), + 75 => Some("WSAResetEvent"), + 76 => Some("WSASend"), + 77 => Some("WSASendDisconnect"), + 78 => Some("WSASendTo"), + 79 => Some("WSASetEvent"), + 80 => Some("WSASetServiceA"), + 81 => Some("WSASetServiceW"), + 82 => Some("WSASocketA"), + 83 => Some("WSASocketW"), + 84 => Some("WSAStringToAddressA"), + 85 => Some("WSAStringToAddressW"), + 86 => Some("WSAWaitForMultipleEvents"), + 87 => Some("WSCDeinstallProvider"), + 88 => Some("WSCEnableNSProvider"), + 89 => Some("WSCEnumProtocols"), + 90 => Some("WSCGetProviderPath"), + 91 => Some("WSCInstallNameSpace"), + 92 => Some("WSCInstallProvider"), + 93 => Some("WSCUnInstallNameSpace"), + 94 => Some("WSCUpdateProvider"), + 95 => Some("WSCWriteNameSpaceOrder"), + 96 => Some("WSCWriteProviderOrder"), + 97 => Some("freeaddrinfo"), + 98 => Some("getaddrinfo"), + 99 => Some("getnameinfo"), + 101 => Some("WSAAsyncSelect"), + 102 => Some("WSAAsyncGetHostByAddr"), + 103 => Some("WSAAsyncGetHostByName"), + 104 => Some("WSAAsyncGetProtoByNumber"), + 105 => Some("WSAAsyncGetProtoByName"), + 106 => Some("WSAAsyncGetServByPort"), + 107 => Some("WSAAsyncGetServByName"), + 108 => Some("WSACancelAsyncRequest"), + 109 => Some("WSASetBlockingHook"), + 110 => Some("WSAUnhookBlockingHook"), + 111 => Some("WSAGetLastError"), + 112 => Some("WSASetLastError"), + 113 => Some("WSACancelBlockingCall"), + 114 => Some("WSAIsBlocking"), + 115 => Some("WSAStartup"), + 116 => Some("WSACleanup"), + 151 => Some("__WSAFDIsSet"), + 500 => Some("WEP"), + _ => None, + } } From 209d8c1b3c1f83069141980652e020f667b0c8e8 Mon Sep 17 00:00:00 2001 From: "Victor M. Alvarez" Date: Tue, 7 Jul 2026 13:27:17 +0200 Subject: [PATCH 3/4] style: run `cargo fmt`. --- lib/src/scanner/mod.rs | 2 +- lib/src/symbols/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/scanner/mod.rs b/lib/src/scanner/mod.rs index ea095c633..cb8bd44b8 100644 --- a/lib/src/scanner/mod.rs +++ b/lib/src/scanner/mod.rs @@ -3,7 +3,6 @@ The scanner takes the rules produces by the compiler and scans data with them. */ use std::collections::BTreeMap; -use rustc_hash::FxHashMap as HashMap; use std::fmt::{Debug, Formatter}; use std::fs; use std::io::Read; @@ -21,6 +20,7 @@ use bitvec::prelude::*; use memmap2::Advice; use memmap2::{Mmap, MmapOptions}; use protobuf::{CodedInputStream, MessageDyn}; +use rustc_hash::FxHashMap as HashMap; use thiserror::Error; use crate::Variable; diff --git a/lib/src/symbols/mod.rs b/lib/src/symbols/mod.rs index 57c457abe..dc6525a45 100644 --- a/lib/src/symbols/mod.rs +++ b/lib/src/symbols/mod.rs @@ -3,10 +3,10 @@ use std::collections::VecDeque; use std::hash::{Hash, Hasher}; use std::rc::Rc; use std::{mem, ptr}; -use rustc_hash::{FxHashMap, FxHashSet}; #[cfg(test)] use bstr::BString; +use rustc_hash::{FxHashMap, FxHashSet}; use crate::compiler::{RuleId, Var}; use crate::types::{AclEntry, DeprecationNotice, Func, Type, TypeValue}; From 0416e7cdc216bf354fdfc6f2c71555fcf589b68a Mon Sep 17 00:00:00 2001 From: 1ndahous3 <9205230+1ndahous3@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:28:06 +0300 Subject: [PATCH 4/4] feat: expose yara.proto from yara-x-proto for custom module builds (#695) This exposes the YARA-X protobuf option schema from the `yara-x-proto` crate so downstream custom modules can import `yara.proto` without vendoring a copy or relying on crate source layout. The new public constants are: ```rust pub const YARA_PROTO_FILE_NAME: &str = "yara.proto"; pub const YARA_PROTO: &str = include_str!("yara.proto"); ``` This lets external module crates use the same protobuf options as in-tree modules while keeping yara.proto owned by yara-x-proto. --- examples/custom-module/Cargo.lock | 208 +++++++++++++++++----- examples/custom-module/Cargo.toml | 3 + examples/custom-module/build.rs | 16 ++ examples/custom-module/proto/foobar.proto | 7 + proto/src/lib.rs | 11 ++ 5 files changed, 203 insertions(+), 42 deletions(-) diff --git a/examples/custom-module/Cargo.lock b/examples/custom-module/Cargo.lock index 3d54358c4..1c1fe4176 100644 --- a/examples/custom-module/Cargo.lock +++ b/examples/custom-module/Cargo.lock @@ -32,6 +32,15 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "annotate-snippets" version = "0.12.16" @@ -169,21 +178,22 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" dependencies = [ "serde_core", ] [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", + "serde", "tap", "wyz", ] @@ -233,6 +243,19 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "cobs" version = "0.3.0" @@ -248,6 +271,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "countme" version = "3.0.1" @@ -468,19 +497,20 @@ dependencies = [ "protobuf", "protobuf-codegen", "yara-x", + "yara-x-proto", ] [[package]] name = "daachorse" -version = "3.0.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d87f75bbe32ee10609201e09e818537df81c3acb436be2b78f47cc85d139475" +checksum = "99251f238b74cd219a86fe6ea9328308ebb223fcbb5b8eb5aa400b847a41dded" [[package]] name = "darling" -version = "0.20.11" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ "darling_core", "darling_macro", @@ -488,11 +518,10 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.11" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", @@ -502,9 +531,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.11" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", "quote", @@ -693,6 +722,7 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ + "crc32fast", "miniz_oxide", "zlib-rs", ] @@ -911,6 +941,30 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "id-arena" version = "2.3.0" @@ -953,9 +1007,9 @@ dependencies = [ [[package]] name = "intaglio" -version = "1.13.3" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e062125b1cb1523e2032c12f3a5bac6947ccd1f8c0a8aae96f63609fe0e34ee" +checksum = "8eca9188c1b20836bb561bc09bb2f54e9ca99b271031b5f3ff183a00c08c98c8" [[package]] name = "inventory" @@ -989,13 +1043,12 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -1114,9 +1167,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "memfd" @@ -1439,9 +1492,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.208" +version = "2.1.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bde51f827dca976f8f9a8c91329a3193114dc076b8012a1ee3624f1588c3582" +checksum = "9826c2fe4dade07e9da1af2e18427257877bc8bc27aa810f6fbb52d907a480cc" dependencies = [ "psl-types", ] @@ -1541,9 +1594,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -1564,9 +1617,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rfc6979" @@ -2008,6 +2061,12 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinyzip" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6847a2bf223d67c916a25d5fb8d197fc1c7c3205421e05d50f3373e092034146" + [[package]] name = "typed-path" version = "0.12.3" @@ -2046,9 +2105,9 @@ checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ "js-sys", "wasm-bindgen", @@ -2078,9 +2137,9 @@ dependencies = [ [[package]] name = "walrus" -version = "0.26.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e151599d689dac80e85c66a7cfa6ffd1b2ab79220517f9161040a87a5041aee3" +checksum = "3bfa49767bb3a9e1afb02aa95bbcbde8d82f2db4ca377afae94d688f14f62378" dependencies = [ "anyhow", "gimli 0.32.3", @@ -2130,9 +2189,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -2143,9 +2202,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2153,9 +2212,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -2166,9 +2225,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] @@ -2425,12 +2484,65 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -2633,9 +2745,15 @@ dependencies = [ "time", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yara-x" -version = "1.16.0" +version = "1.19.0" dependencies = [ "annotate-snippets", "anyhow", @@ -2651,6 +2769,7 @@ dependencies = [ "digest", "dsa", "ecdsa", + "flate2", "getrandom 0.2.17", "globwalk", "hex", @@ -2688,6 +2807,7 @@ dependencies = [ "smallvec", "strum_macros", "thiserror 2.0.18", + "tinyzip", "uuid", "walrus", "wasm-bindgen", @@ -2701,7 +2821,7 @@ dependencies = [ [[package]] name = "yara-x-macros" -version = "1.16.0" +version = "1.19.0" dependencies = [ "darling", "proc-macro2", @@ -2711,7 +2831,7 @@ dependencies = [ [[package]] name = "yara-x-parser" -version = "1.16.0" +version = "1.19.0" dependencies = [ "ascii_tree", "bitflags", @@ -2727,10 +2847,14 @@ dependencies = [ [[package]] name = "yara-x-proto" -version = "1.16.0" +version = "1.19.0" dependencies = [ + "base64", + "chrono", + "itertools", "protobuf", "protobuf-codegen", + "yansi", ] [[package]] diff --git a/examples/custom-module/Cargo.toml b/examples/custom-module/Cargo.toml index b499c0b75..9885c34a3 100644 --- a/examples/custom-module/Cargo.toml +++ b/examples/custom-module/Cargo.toml @@ -24,3 +24,6 @@ protobuf = "3.7.2" # Compiles `proto/custom_test.proto` into Rust code at build time. The # `pure` mode is selected so that no external `protoc` binary is required. protobuf-codegen = "3.7.2" +# Provides `yara.proto`, which defines the custom protobuf options used by +# YARA-X module schemas. +yara-x-proto = { path = "../../proto" } diff --git a/examples/custom-module/build.rs b/examples/custom-module/build.rs index 31d75dfc9..dc374c1f4 100644 --- a/examples/custom-module/build.rs +++ b/examples/custom-module/build.rs @@ -2,10 +2,26 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=proto"); + let out_dir = std::path::PathBuf::from( + std::env::var_os("OUT_DIR").expect("OUT_DIR must be set"), + ); + let yara_proto_dir = out_dir.join("yara-proto"); + std::fs::create_dir_all(&yara_proto_dir) + .expect("failed to create yara.proto include directory"); + std::fs::write( + yara_proto_dir.join(yara_x_proto::YARA_PROTO_FILE_NAME), + yara_x_proto::YARA_PROTO, + ) + .expect("failed to write yara.proto"); + let yara_proto_path = + yara_proto_dir.join(yara_x_proto::YARA_PROTO_FILE_NAME); + protobuf_codegen::Codegen::new() .pure() .cargo_out_dir("protos") .include("proto") + .include(yara_proto_dir) + .input(yara_proto_path) .input("proto/foobar.proto") .run_from_script(); } diff --git a/examples/custom-module/proto/foobar.proto b/examples/custom-module/proto/foobar.proto index 8232aac2b..5dfbfa97a 100644 --- a/examples/custom-module/proto/foobar.proto +++ b/examples/custom-module/proto/foobar.proto @@ -2,6 +2,13 @@ syntax = "proto2"; package foobar; +import "yara.proto"; + +option (yara.module_options) = { + name: "foobar" + root_message: "foobar.Foobar" +}; + message Foobar { optional uint64 count = 1; optional string label = 2; diff --git a/proto/src/lib.rs b/proto/src/lib.rs index 5ec0bff78..55704b943 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -6,6 +6,17 @@ use crate::yara::exts::field_options; include!(concat!(env!("OUT_DIR"), "/protos/mod.rs")); +/// File name used by the protobuf extension definitions consumed by YARA-X +/// module schemas. +pub const YARA_PROTO_FILE_NAME: &str = "yara.proto"; + +/// Protobuf extension definitions used by YARA-X module schemas. +/// +/// Downstream crates that generate protobuf-backed YARA-X modules can write +/// this content to their build output directory and add that directory to their +/// `protobuf_codegen::Codegen` include paths. +pub const YARA_PROTO: &str = include_str!("yara.proto"); + /// Possible formats applied to values in YARA modules. /// /// In the protobufs defining a YARA module, values can be formatted in various