diff --git a/Cargo.lock b/Cargo.lock index 0c59222e..d4be2556 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arbitrary" @@ -309,9 +309,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" dependencies = [ "serde_core", ] @@ -340,13 +340,13 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" dependencies = [ "memchr", "regex-automata", - "serde", + "serde_core", ] [[package]] @@ -465,9 +465,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "dd059f9da4f5c36b3787f65d38ccaab1cc315f07b01f89abc8359ee6a8205011" dependencies = [ "clap_builder", "clap_derive", @@ -475,9 +475,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b" dependencies = [ "anstream", "anstyle", @@ -487,9 +487,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.6.5" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772" +checksum = "db8b397918185f0161ff3d6fcaa9e4bfc09b8367caf6e1d4a2848e5477ed027b" dependencies = [ "clap", ] @@ -854,7 +854,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossterm_winapi", "derive_more", "document-features", @@ -905,9 +905,9 @@ dependencies = [ [[package]] name = "daachorse" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99251f238b74cd219a86fe6ea9328308ebb223fcbb5b8eb5aa400b847a41dded" +checksum = "5614204febbc33cc07a2806aa6440b904ac012b68eecc37f4493ea4a76455a3d" [[package]] name = "darling" @@ -1460,7 +1460,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "ignore", "walkdir", ] @@ -1993,7 +1993,7 @@ version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50ecbc2953846d9a3f8f6ed0700e66e49e5ad696eefb4e17fbaebbf457e1e752" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "magic-sys", ] @@ -2696,7 +2696,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -2725,7 +2725,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -2858,7 +2858,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2871,7 +2871,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -3707,9 +3707,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.3" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" dependencies = [ "js-sys", "wasm-bindgen", @@ -3911,7 +3911,7 @@ version = "0.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "hashbrown 0.16.1", "indexmap", "semver", @@ -3937,7 +3937,7 @@ checksum = "efb1ed5899dde98357cfdcf647a4614498798719793898245b4b34e663addabf" dependencies = [ "addr2line", "async-trait", - "bitflags 2.13.0", + "bitflags 2.13.1", "bumpalo", "cc", "cfg-if", @@ -4444,7 +4444,7 @@ dependencies = [ "anyhow", "base64", "bincode", - "bitflags 2.13.0", + "bitflags 2.13.1", "bitvec", "bstr", "codepage", @@ -4568,7 +4568,7 @@ dependencies = [ name = "yara-x-fmt" version = "1.19.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "bstr", "globwalk", "goldenfile", @@ -4599,7 +4599,7 @@ name = "yara-x-ls" version = "1.19.0" dependencies = [ "async-lsp", - "bitflags 2.13.0", + "bitflags 2.13.1", "chrono", "console_error_panic_hook", "dashmap", @@ -4640,7 +4640,7 @@ version = "1.19.0" dependencies = [ "anyhow", "ascii_tree", - "bitflags 2.13.0", + "bitflags 2.13.1", "bstr", "env_logger", "globwalk", diff --git a/Cargo.toml b/Cargo.toml index cec57450..5b168736 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,20 +31,20 @@ resolver = "3" [workspace.dependencies] -daachorse = "3.0.2" +daachorse = "3.0.3" annotate-snippets = "0.12.16" -anyhow = "1.0.102" +anyhow = "1.0.103" hex = "0.4.3" ascii_tree = "0.1.1" base64 = "0.22.1" bincode = "2.0.1" -bitflags = "2.13.0" +bitflags = "2.13.1" bitvec = "1.1.1" -bstr = "1.12.1" +bstr = "1.13.0" cbindgen = "0.29.4" chrono = "0.4.45" -clap = "4.6.1" -clap_complete = "4.6.5" +clap = "4.6.2" +clap_complete = "4.6.7" codepage = "0.1.2" const-oid = "0.9.6" crc32fast = "1.5.0" @@ -102,7 +102,7 @@ smallvec = "1.14.0" strum = "0.28.0" strum_macros = "0.28.0" thiserror = "2.0.18" -uuid = "1.23.3" +uuid = "1.24.0" walrus = "0.26.4" wasm-bindgen = "0.2.125" wasm-bindgen-test = "0.3.75" diff --git a/lib/src/compiler/rules.rs b/lib/src/compiler/rules.rs index 7df2d71f..0ccff08e 100644 --- a/lib/src/compiler/rules.rs +++ b/lib/src/compiler/rules.rs @@ -1,3 +1,4 @@ +use std::collections::hash_map; use std::fmt; use std::io::{BufWriter, Read, Write}; use std::ops::{Bound, RangeBounds}; @@ -669,17 +670,15 @@ impl Rules { #[inline] pub(crate) fn filesize_bounds( &self, - pattern_id: PatternId, - ) -> Option<&FilesizeBounds> { - self.filesize_bounds.get(&pattern_id) + ) -> hash_map::Iter<'_, PatternId, FilesizeBounds> { + self.filesize_bounds.iter() } #[inline] pub(crate) fn header_constraints( &self, - pattern_id: PatternId, - ) -> Option<&HeaderConstraint> { - self.header_constraints.get(&pattern_id) + ) -> hash_map::Iter<'_, PatternId, HeaderConstraint> { + self.header_constraints.iter() } #[inline] diff --git a/lib/src/modules/pe/tests/testdata/85a938cb2058604229f335b2f109aaec203e78695d54e1a7874b0fd5ac80568b.in.zip b/lib/src/modules/pe/tests/testdata/85a938cb2058604229f335b2f109aaec203e78695d54e1a7874b0fd5ac80568b.in.zip new file mode 100644 index 00000000..ac02326b Binary files /dev/null and b/lib/src/modules/pe/tests/testdata/85a938cb2058604229f335b2f109aaec203e78695d54e1a7874b0fd5ac80568b.in.zip differ diff --git a/lib/src/modules/pe/tests/testdata/85a938cb2058604229f335b2f109aaec203e78695d54e1a7874b0fd5ac80568b.out b/lib/src/modules/pe/tests/testdata/85a938cb2058604229f335b2f109aaec203e78695d54e1a7874b0fd5ac80568b.out new file mode 100644 index 00000000..2d1cdc46 --- /dev/null +++ b/lib/src/modules/pe/tests/testdata/85a938cb2058604229f335b2f109aaec203e78695d54e1a7874b0fd5ac80568b.out @@ -0,0 +1,458 @@ +is_pe: true +machine: MACHINE_I386 +subsystem: SUBSYSTEM_WINDOWS_CUI +os_version: + major: 4 + minor: 0 +subsystem_version: + major: 4 + minor: 0 +image_version: + major: 0 + minor: 0 +linker_version: + major: 0 + minor: 0 +opthdr_magic: IMAGE_NT_OPTIONAL_HDR32_MAGIC +characteristics: 0x102 # EXECUTABLE_IMAGE | MACHINE_32BIT +dll_characteristics: 0x0 +timestamp: 0 # 1970-01-01 00:00:00 UTC +image_base: 0x400000 +checksum: 0 +base_of_code: 0x1000 +base_of_data: 0x2000 +entry_point: 0x200 +entry_point_raw: 0x1000 +section_alignment: 0x1000 +file_alignment: 0x200 +loader_flags: 0x0 +size_of_optional_header: 0xe0 +size_of_code: 0x400 +size_of_initialized_data: 0x400 +size_of_uninitialized_data: 0x0 +size_of_image: 0x3000 +size_of_headers: 0x200 +size_of_stack_reserve: 0x100000 +size_of_stack_commit: 0x1000 +size_of_heap_reserve: 0x100000 +size_of_heap_commit: 0x1000 +pointer_to_symbol_table: 0x0 +win32_version_value: 0 +number_of_symbols: 0 +number_of_rva_and_sizes: 16 +number_of_sections: 1 +number_of_imported_functions: 118 +number_of_delayed_imported_functions: 0 +number_of_resources: 0 +number_of_version_infos: 0 +number_of_imports: 1 +number_of_delayed_imports: 0 +number_of_exports: 0 +number_of_signatures: 0 +sections: + - name: ".text" + full_name: ".text" + characteristics: 0x60000020 # SECTION_MEM_READ | SECTION_MEM_WRITE | SECTION_SCALE_INDEX + raw_data_size: 0x400 + raw_data_offset: 0x200 + virtual_address: 0x1000 + virtual_size: 0x1000 + pointer_to_relocations: 0x0 + pointer_to_line_numbers: 0x0 + number_of_relocations: 0 + number_of_line_numbers: 0 +data_directories: + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x1000 + size: 0x200 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 + - virtual_address: 0x0 + size: 0x0 +import_details: + - library_name: "wsock32.dll" + number_of_functions: 118 + functions: + - name: "accept" + ordinal: 1 + rva: 0x1040 + - name: "bind" + ordinal: 2 + rva: 0x1044 + - name: "closesocket" + ordinal: 3 + rva: 0x1048 + - name: "connect" + ordinal: 4 + rva: 0x104c + - name: "getpeername" + ordinal: 5 + rva: 0x1050 + - name: "getsockname" + ordinal: 6 + rva: 0x1054 + - name: "getsockopt" + ordinal: 7 + rva: 0x1058 + - name: "htonl" + ordinal: 8 + rva: 0x105c + - name: "htons" + ordinal: 9 + rva: 0x1060 + - name: "ioctlsocket" + ordinal: 10 + rva: 0x1064 + - name: "inet_addr" + ordinal: 11 + rva: 0x1068 + - name: "inet_ntoa" + ordinal: 12 + rva: 0x106c + - name: "listen" + ordinal: 13 + rva: 0x1070 + - name: "ntohl" + ordinal: 14 + rva: 0x1074 + - name: "ntohs" + ordinal: 15 + rva: 0x1078 + - name: "recv" + ordinal: 16 + rva: 0x107c + - name: "recvfrom" + ordinal: 17 + rva: 0x1080 + - name: "select" + ordinal: 18 + rva: 0x1084 + - name: "send" + ordinal: 19 + rva: 0x1088 + - name: "sendto" + ordinal: 20 + rva: 0x108c + - name: "setsockopt" + ordinal: 21 + rva: 0x1090 + - name: "shutdown" + ordinal: 22 + rva: 0x1094 + - name: "socket" + ordinal: 23 + rva: 0x1098 + - name: "GetAddrInfoW" + ordinal: 24 + rva: 0x109c + - name: "GetNameInfoW" + ordinal: 25 + rva: 0x10a0 + - name: "WSApSetPostRoutine" + ordinal: 26 + rva: 0x10a4 + - name: "FreeAddrInfoW" + ordinal: 27 + rva: 0x10a8 + - name: "WPUCompleteOverlappedRequest" + ordinal: 28 + rva: 0x10ac + - name: "WSAAccept" + ordinal: 29 + rva: 0x10b0 + - name: "WSAAddressToStringA" + ordinal: 30 + rva: 0x10b4 + - name: "WSAAddressToStringW" + ordinal: 31 + rva: 0x10b8 + - name: "WSACloseEvent" + ordinal: 32 + rva: 0x10bc + - name: "WSAConnect" + ordinal: 33 + rva: 0x10c0 + - name: "WSACreateEvent" + ordinal: 34 + rva: 0x10c4 + - name: "WSADuplicateSocketA" + ordinal: 35 + rva: 0x10c8 + - name: "WSADuplicateSocketW" + ordinal: 36 + rva: 0x10cc + - name: "WSAEnumNameSpaceProvidersA" + ordinal: 37 + rva: 0x10d0 + - name: "WSAEnumNameSpaceProvidersW" + ordinal: 38 + rva: 0x10d4 + - name: "WSAEnumNetworkEvents" + ordinal: 39 + rva: 0x10d8 + - name: "WSAEnumProtocolsA" + ordinal: 40 + rva: 0x10dc + - name: "WSAEnumProtocolsW" + ordinal: 41 + rva: 0x10e0 + - name: "WSAEventSelect" + ordinal: 42 + rva: 0x10e4 + - name: "WSAGetOverlappedResult" + ordinal: 43 + rva: 0x10e8 + - name: "WSAGetQOSByName" + ordinal: 44 + rva: 0x10ec + - name: "WSAGetServiceClassInfoA" + ordinal: 45 + rva: 0x10f0 + - name: "WSAGetServiceClassInfoW" + ordinal: 46 + rva: 0x10f4 + - name: "WSAGetServiceClassNameByClassIdA" + ordinal: 47 + rva: 0x10f8 + - name: "WSAGetServiceClassNameByClassIdW" + ordinal: 48 + rva: 0x10fc + - name: "WSAHtonl" + ordinal: 49 + rva: 0x1100 + - name: "WSAHtons" + ordinal: 50 + rva: 0x1104 + - name: "gethostbyaddr" + ordinal: 51 + rva: 0x1108 + - name: "gethostbyname" + ordinal: 52 + rva: 0x110c + - name: "getprotobyname" + ordinal: 53 + rva: 0x1110 + - name: "getprotobynumber" + ordinal: 54 + rva: 0x1114 + - name: "getservbyname" + ordinal: 55 + rva: 0x1118 + - name: "getservbyport" + ordinal: 56 + rva: 0x111c + - name: "gethostname" + ordinal: 57 + rva: 0x1120 + - name: "WSAInstallServiceClassA" + ordinal: 58 + rva: 0x1124 + - name: "WSAInstallServiceClassW" + ordinal: 59 + rva: 0x1128 + - name: "WSAIoctl" + ordinal: 60 + rva: 0x112c + - name: "WSAJoinLeaf" + ordinal: 61 + rva: 0x1130 + - name: "WSALookupServiceBeginA" + ordinal: 62 + rva: 0x1134 + - name: "WSALookupServiceBeginW" + ordinal: 63 + rva: 0x1138 + - name: "WSALookupServiceEnd" + ordinal: 64 + rva: 0x113c + - name: "WSALookupServiceNextA" + ordinal: 65 + rva: 0x1140 + - name: "WSALookupServiceNextW" + ordinal: 66 + rva: 0x1144 + - name: "WSANSPIoctl" + ordinal: 67 + rva: 0x1148 + - name: "WSANtohl" + ordinal: 68 + rva: 0x114c + - name: "WSANtohs" + ordinal: 69 + rva: 0x1150 + - name: "WSAProviderConfigChange" + ordinal: 70 + rva: 0x1154 + - name: "WSARecv" + ordinal: 71 + rva: 0x1158 + - name: "WSARecvDisconnect" + ordinal: 72 + rva: 0x115c + - name: "WSARecvFrom" + ordinal: 73 + rva: 0x1160 + - name: "WSARemoveServiceClass" + ordinal: 74 + rva: 0x1164 + - name: "WSAResetEvent" + ordinal: 75 + rva: 0x1168 + - name: "WSASend" + ordinal: 76 + rva: 0x116c + - name: "WSASendDisconnect" + ordinal: 77 + rva: 0x1170 + - name: "WSASendTo" + ordinal: 78 + rva: 0x1174 + - name: "WSASetEvent" + ordinal: 79 + rva: 0x1178 + - name: "WSASetServiceA" + ordinal: 80 + rva: 0x117c + - name: "WSASetServiceW" + ordinal: 81 + rva: 0x1180 + - name: "WSASocketA" + ordinal: 82 + rva: 0x1184 + - name: "WSASocketW" + ordinal: 83 + rva: 0x1188 + - name: "WSAStringToAddressA" + ordinal: 84 + rva: 0x118c + - name: "WSAStringToAddressW" + ordinal: 85 + rva: 0x1190 + - name: "WSAWaitForMultipleEvents" + ordinal: 86 + rva: 0x1194 + - name: "WSCDeinstallProvider" + ordinal: 87 + rva: 0x1198 + - name: "WSCEnableNSProvider" + ordinal: 88 + rva: 0x119c + - name: "WSCEnumProtocols" + ordinal: 89 + rva: 0x11a0 + - name: "WSCGetProviderPath" + ordinal: 90 + rva: 0x11a4 + - name: "WSCInstallNameSpace" + ordinal: 91 + rva: 0x11a8 + - name: "WSCInstallProvider" + ordinal: 92 + rva: 0x11ac + - name: "WSCUnInstallNameSpace" + ordinal: 93 + rva: 0x11b0 + - name: "WSCUpdateProvider" + ordinal: 94 + rva: 0x11b4 + - name: "WSCWriteNameSpaceOrder" + ordinal: 95 + rva: 0x11b8 + - name: "WSCWriteProviderOrder" + ordinal: 96 + rva: 0x11bc + - name: "freeaddrinfo" + ordinal: 97 + rva: 0x11c0 + - name: "getaddrinfo" + ordinal: 98 + rva: 0x11c4 + - name: "getnameinfo" + ordinal: 99 + rva: 0x11c8 + - name: "WSAAsyncSelect" + ordinal: 101 + rva: 0x11cc + - name: "WSAAsyncGetHostByAddr" + ordinal: 102 + rva: 0x11d0 + - name: "WSAAsyncGetHostByName" + ordinal: 103 + rva: 0x11d4 + - name: "WSAAsyncGetProtoByNumber" + ordinal: 104 + rva: 0x11d8 + - name: "WSAAsyncGetProtoByName" + ordinal: 105 + rva: 0x11dc + - name: "WSAAsyncGetServByPort" + ordinal: 106 + rva: 0x11e0 + - name: "WSAAsyncGetServByName" + ordinal: 107 + rva: 0x11e4 + - name: "WSACancelAsyncRequest" + ordinal: 108 + rva: 0x11e8 + - name: "WSASetBlockingHook" + ordinal: 109 + rva: 0x11ec + - name: "WSAUnhookBlockingHook" + ordinal: 110 + rva: 0x11f0 + - name: "WSAGetLastError" + ordinal: 111 + rva: 0x11f4 + - name: "WSASetLastError" + ordinal: 112 + rva: 0x11f8 + - name: "WSACancelBlockingCall" + ordinal: 113 + rva: 0x11fc + - name: "WSAIsBlocking" + ordinal: 114 + rva: 0x1200 + - name: "WSAStartup" + ordinal: 115 + rva: 0x1204 + - name: "WSACleanup" + ordinal: 116 + rva: 0x1208 + - name: "__WSAFDIsSet" + ordinal: 151 + rva: 0x120c + - name: "WEP" + ordinal: 500 + rva: 0x1210 + - name: "ord999" + ordinal: 999 + rva: 0x1214 +is_signed: false +overlay: + offset: 0x0 + size: 0x0 \ No newline at end of file diff --git a/lib/src/scanner/context.rs b/lib/src/scanner/context.rs index 44fb0eff..57fac190 100644 --- a/lib/src/scanner/context.rs +++ b/lib/src/scanner/context.rs @@ -903,6 +903,20 @@ impl ScanContext<'_, '_> { ); } + #[cfg(feature = "rules-profiling")] + { + let time_spent = self + .clock + .delta_as_nanos(verification_start, self.clock.raw()); + + self.time_spent_in_pattern + .entry(*pattern_id) + .and_modify(|t| { + t.add_assign(time_spent); + }) + .or_insert(time_spent); + } + return; } @@ -1102,6 +1116,9 @@ impl ScanContext<'_, '_> { /// In case of timeout, this function returns [ScanError::Timeout] and sets /// the scan state to [ScanState::Timeout]. pub(crate) fn search_for_patterns(&mut self) -> Result<(), ScanError> { + #[cfg(any(feature = "rules-profiling", feature = "logging"))] + let scan_start = self.clock.raw(); + // Take ownership of the scan state, while searching for // the patterns, `self.scan_state` is left as `Idle`. let state = self.scan_state.take(); @@ -1114,32 +1131,23 @@ impl ScanContext<'_, '_> { if !block_scanning_mode { let filesize = self.get_filesize(); - for pattern_id in 0..self.compiled_rules.num_patterns() { - let pattern_id = PatternId::from(pattern_id); - if let Some(bounds) = - self.compiled_rules.filesize_bounds(pattern_id) - && !bounds.contains(filesize) - { - self.tracker.disabled_patterns.insert(pattern_id); + for (pattern_id, bounds) in self.compiled_rules.filesize_bounds() { + if !bounds.contains(filesize) { + self.tracker.disabled_patterns.insert(*pattern_id); } } } if base == 0 { - for pattern_id in 0..self.compiled_rules.num_patterns() { - let pattern_id = PatternId::from(pattern_id); - if let Some(constraints) = - self.compiled_rules.header_constraints(pattern_id) - && !constraints.is_satisfied(data) - { - self.tracker.disabled_patterns.insert(pattern_id); + for (pattern_id, constraints) in + self.compiled_rules.header_constraints() + { + if !constraints.is_satisfied(data) { + self.tracker.disabled_patterns.insert(*pattern_id); } } } - #[cfg(any(feature = "rules-profiling", feature = "logging"))] - let scan_start = self.clock.raw(); - // Verify the anchored pattern first. These are patterns that can // match at a single known offset within the data. self.verify_anchored_patterns(base, data); diff --git a/py/src/lib.rs b/py/src/lib.rs index 7af16985..edf57ac2 100644 --- a/py/src/lib.rs +++ b/py/src/lib.rs @@ -437,6 +437,27 @@ impl Module { } } +/// Reasons a rule can be ignored by the compiler. +#[pyclass(eq, eq_int, from_py_object)] +#[derive(PartialEq, Clone)] +enum IgnoredRuleReason { + IgnoredModule, + IgnoredRule, + CompileError, +} + +/// Structure that represents invalid rules by the compiler. See +/// [`Compiler::ignore_invalid_rules`]. +#[pyclass] +struct IgnoredRule { + #[pyo3(get)] + name: String, + #[pyo3(get)] + message: String, + #[pyo3(get)] + reason: IgnoredRuleReason, +} + /// Returns the names of the supported modules. /// /// These are the modules that can be used in `import` statements in your @@ -465,6 +486,7 @@ struct Compiler { relaxed_re_syntax: bool, error_on_slow_pattern: bool, includes_enabled: bool, + ignore_invalid_rules: bool, } impl Compiler { @@ -497,19 +519,24 @@ impl Compiler { /// /// The `error_on_slow_pattern` argument tells the compiler to treat slow /// patterns as errors, instead of warnings. + /// + /// `ignore_invalid_rules` argument tells the compiler to report reasons for + /// ignoring invalid rules in [`Compiler::ignored_rules`]. #[new] - #[pyo3(signature = (relaxed_re_syntax=false, error_on_slow_pattern=false, includes_enabled=true) + #[pyo3(signature = (relaxed_re_syntax=false, error_on_slow_pattern=false, includes_enabled=true, ignore_invalid_rules=false) )] fn new( relaxed_re_syntax: bool, error_on_slow_pattern: bool, includes_enabled: bool, + ignore_invalid_rules: bool, ) -> Self { let mut compiler = Self { inner: Self::new_inner(relaxed_re_syntax, error_on_slow_pattern), relaxed_re_syntax, error_on_slow_pattern, includes_enabled, + ignore_invalid_rules, }; compiler.inner.enable_includes(includes_enabled); compiler @@ -564,9 +591,14 @@ impl Compiler { src = src.with_origin(origin) } - self.inner - .add_source(src) - .map_err(|err| CompileError::new_err(err.to_string()))?; + match self.inner.add_source(src) { + Ok(_) => {} + Err(err) => { + if !self.ignore_invalid_rules { + return Err(CompileError::new_err(err.to_string())); + } + } + }; Ok(()) } @@ -685,6 +717,20 @@ impl Compiler { self.inner.max_warnings(n); } + /// Enables or disables ignoring invalid rules. If `True` the ignored rules + /// and the reasons for them being ignored are available in + /// [`Compiler::ignored_rules`] method. + /// + /// # Example + /// ```python + /// import yara_x + /// + /// compiler = yara_x.Compiler() + /// compiler.ignore_invalid_rules(True) + /// ``` + fn ignore_invalid_rules(&mut self, yes: bool) { + self.ignore_invalid_rules = yes + } /// Builds the source code previously added to the compiler. /// /// This function returns an instance of [`Rules`] containing all the rules @@ -731,6 +777,37 @@ impl Compiler { json_loads.call((warnings_json,), None) } + /// Retrieves all ignored rules from the compiler. + /// + /// Returns a list of tuples where the first item is the rule name and the + /// second item is the reason. + fn ignored_rules(&self) -> Vec { + self.inner + .ignored_rules() + .map(|(name, reason)| { + let (message, reason_type) = match reason { + yrx::IgnoredRuleReason::IgnoredModule(module) => ( + format!("depends on ignored module `{module}`"), + IgnoredRuleReason::IgnoredModule, + ), + yrx::IgnoredRuleReason::IgnoredRule(parent_rule) => ( + format!("depends on ignored rule `{parent_rule}`"), + IgnoredRuleReason::IgnoredRule, + ), + yrx::IgnoredRuleReason::CompileError(err) => ( + format!("error: {}", err.title()), + IgnoredRuleReason::CompileError, + ), + }; + IgnoredRule { + name: name.to_string(), + message, + reason: reason_type, + } + }) + .collect() + } + #[pyo3(signature = (tags, error = false))] fn allowed_tags( &mut self, @@ -1574,6 +1651,8 @@ fn yara_x(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; // This module still exposes unsendable classes and uses unsafe lifetime // extensions in the bindings, so it should not advertise free-threaded // safety until the API is properly audited and redesigned. diff --git a/py/tests/test_api.py b/py/tests/test_api.py index 1b7f6e2f..1dd487fa 100644 --- a/py/tests/test_api.py +++ b/py/tests/test_api.py @@ -40,6 +40,27 @@ def test_invalid_allowed_metadata_regexp(): with pytest.raises(ValueError): compiler.allowed_metadata('author', yara_x.MetaType.STRING, regexp='(AXS|ERS') +def test_ignore_invalid_rules(): + compiler = yara_x.Compiler(ignore_invalid_rules=True) + compiler.ignore_module("foo") + # "test" should be ignored because it depends on an ignored module. + # "test2" should be ignored because it depends on an ignored rule (test). + # "test3" should be ignored because it is a compilation error. + compiler.add_source(r'import "foo" rule test { condition: foo.bar == 1 } rule test2 { condition: test } rule test3 { condition: AXSERS }') + assert len(compiler.ignored_rules()) == 3 + assert compiler.ignored_rules()[0].name == 'test' + assert compiler.ignored_rules()[0].message == 'depends on ignored module `foo`' + assert compiler.ignored_rules()[0].reason == yara_x.IgnoredRuleReason.IgnoredModule + assert compiler.ignored_rules()[1].name == 'test2' + assert compiler.ignored_rules()[1].message == 'depends on ignored rule `test`' + assert compiler.ignored_rules()[1].reason == yara_x.IgnoredRuleReason.IgnoredRule + assert compiler.ignored_rules()[2].name == 'test3' + assert compiler.ignored_rules()[2].message == 'error: unknown identifier `AXSERS`' + assert compiler.ignored_rules()[2].reason == yara_x.IgnoredRuleReason.CompileError + # Turn off ignore_invalid_rules and we should raise a compile error now. + compiler.ignore_invalid_rules(False) + with pytest.raises(yara_x.CompileError): + compiler.add_source(r'rule test { condition: AXSERS }') def test_int_globals(): compiler = yara_x.Compiler() diff --git a/py/yara_x.pyi b/py/yara_x.pyi index 21faaad3..31480f03 100644 --- a/py/yara_x.pyi +++ b/py/yara_x.pyi @@ -135,6 +135,23 @@ class Compiler: """ ... + def ignore_invalid_rules(self, yes: bool) -> None: + r""" + Tell the compiler to ignore any rules that are invalid. + + Any ignored rules and the reasons for them being ignored are available + in [`Compiler::ignored_rules`]. + """ + ... + + def ignored_rules() -> List[IgnoredRule]: + r""" + Retrieve all ignored rules during compilation. + + Returns a list of [`IgnoredRule`] objects. + """ + ... + def build(self) -> Rules: r""" Builds the source code previously added to the compiler. @@ -193,6 +210,37 @@ class Compiler: r"""Define expected type and value for metadata on rules.""" ... +@final +class IgnoredRuleReason(Enum): + IgnoredModule: int + IgnoredRule: int + CompileError: int + +@final +class IgnoredRule: + r""" + Names and reasons for any ignored rules during compilation. + + See [`Compiler::ignore_invalid_rules] for details. + """ + def name() -> str: + r""" + Name of the ignored rule. + """ + ... + + def message() -> str: + r""" + Message for why the rule was ignored. + """ + ... + + def reason() -> IgnoredRuleReason: + r""" + Reason for why the rule was ignored. + """ + ... + @final class ScanOptions: r"""