maco 1.2.17__py3-none-any.whl → 1.2.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- extractor_setup/maco/__init__.py +0 -0
- extractor_setup/maco/base_test.py +98 -0
- extractor_setup/maco/cli.py +275 -0
- extractor_setup/maco/collector.py +220 -0
- extractor_setup/maco/exceptions.py +33 -0
- extractor_setup/maco/extractor.py +70 -0
- extractor_setup/maco/model/__init__.py +1 -0
- extractor_setup/maco/model/model.py +606 -0
- extractor_setup/maco/utils.py +587 -0
- extractor_setup/maco/yara.py +129 -0
- maco/utils.py +2 -2
- {maco-1.2.17.dist-info → maco-1.2.18.dist-info}/METADATA +2 -1
- {maco-1.2.17.dist-info → maco-1.2.18.dist-info}/RECORD +19 -9
- {maco-1.2.17.dist-info → maco-1.2.18.dist-info}/top_level.txt +1 -0
- model_setup/maco/utils.py +2 -2
- pipelines/publish.yaml +30 -24
- {maco-1.2.17.dist-info → maco-1.2.18.dist-info}/WHEEL +0 -0
- {maco-1.2.17.dist-info → maco-1.2.18.dist-info}/entry_points.txt +0 -0
- {maco-1.2.17.dist-info → maco-1.2.18.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""yara-python facade that uses yara-x."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from collections import namedtuple
|
|
5
|
+
from itertools import cycle
|
|
6
|
+
from typing import Dict, List, Union
|
|
7
|
+
|
|
8
|
+
import yara_x
|
|
9
|
+
|
|
10
|
+
from maco.exceptions import SyntaxError
|
|
11
|
+
|
|
12
|
+
RULE_ID_RE = re.compile("(\w+)? ?rule (\w+)")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Create interfaces that resembles yara-python (but is running yara-x under the hood)
|
|
16
|
+
class StringMatchInstance:
|
|
17
|
+
"""Instance of a string match."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, match: yara_x.Match, file_content: bytes):
|
|
20
|
+
"""Initializes StringMatchInstance."""
|
|
21
|
+
self.matched_data = file_content[match.offset : match.offset + match.length]
|
|
22
|
+
self.matched_length = match.length
|
|
23
|
+
self.offset = match.offset
|
|
24
|
+
self.xor_key = match.xor_key
|
|
25
|
+
|
|
26
|
+
def plaintext(self) -> bytes:
|
|
27
|
+
"""Plaintext of the matched data.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
(bytes): Plaintext of the matched cipher text
|
|
31
|
+
"""
|
|
32
|
+
if not self.xor_key:
|
|
33
|
+
# No need to XOR the matched data
|
|
34
|
+
return self.matched_data
|
|
35
|
+
else:
|
|
36
|
+
return bytes(c ^ k for c, k in zip(self.matched_data, cycle(self.xor_key)))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class StringMatch:
|
|
40
|
+
"""String match."""
|
|
41
|
+
|
|
42
|
+
def __init__(self, pattern: yara_x.Pattern, file_content: bytes):
|
|
43
|
+
"""Initializes StringMatch."""
|
|
44
|
+
self.identifier = pattern.identifier
|
|
45
|
+
self.instances = [StringMatchInstance(match, file_content) for match in pattern.matches]
|
|
46
|
+
self._is_xor = any([match.xor_key for match in pattern.matches])
|
|
47
|
+
|
|
48
|
+
def is_xor(self):
|
|
49
|
+
"""Checks if string match is xor'd.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
(bool): True if match is xor'd
|
|
53
|
+
"""
|
|
54
|
+
return self._is_xor
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Match:
|
|
58
|
+
"""Match."""
|
|
59
|
+
|
|
60
|
+
def __init__(self, rule: yara_x.Rule, file_content: bytes):
|
|
61
|
+
"""Initializes Match."""
|
|
62
|
+
self.rule = rule.identifier
|
|
63
|
+
self.namespace = rule.namespace
|
|
64
|
+
self.tags = list(rule.tags) or []
|
|
65
|
+
self.meta = dict()
|
|
66
|
+
# Ensure metadata doesn't get overwritten
|
|
67
|
+
for k, v in rule.metadata:
|
|
68
|
+
self.meta.setdefault(k, []).append(v)
|
|
69
|
+
self.strings = [StringMatch(pattern, file_content) for pattern in rule.patterns]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Rules:
|
|
73
|
+
"""Rules."""
|
|
74
|
+
|
|
75
|
+
def __init__(self, source: str = None, sources: Dict[str, str] = None):
|
|
76
|
+
"""Initializes Rules.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
SyntaxError: Raised when there's a syntax error in the YARA rule.
|
|
80
|
+
"""
|
|
81
|
+
Rule = namedtuple("Rule", "identifier namespace is_global")
|
|
82
|
+
if source:
|
|
83
|
+
sources = {"default": source}
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
self._rules = []
|
|
87
|
+
compiler = yara_x.Compiler(relaxed_re_syntax=True)
|
|
88
|
+
for namespace, source in sources.items():
|
|
89
|
+
compiler.new_namespace(namespace)
|
|
90
|
+
for rule_type, id in RULE_ID_RE.findall(source):
|
|
91
|
+
is_global = True if rule_type == "global" else False
|
|
92
|
+
self._rules.append(Rule(namespace=namespace, identifier=id, is_global=is_global))
|
|
93
|
+
compiler.add_source(source)
|
|
94
|
+
self.scanner = yara_x.Scanner(compiler.build())
|
|
95
|
+
except yara_x.CompileError as e:
|
|
96
|
+
raise SyntaxError(e)
|
|
97
|
+
|
|
98
|
+
def __iter__(self):
|
|
99
|
+
"""Iterate over rules.
|
|
100
|
+
|
|
101
|
+
Yields:
|
|
102
|
+
YARA rules
|
|
103
|
+
"""
|
|
104
|
+
for rule in self._rules:
|
|
105
|
+
yield rule
|
|
106
|
+
|
|
107
|
+
def match(self, filepath: str = None, data: Union[bytes, bytearray] = None) -> List[Match]:
|
|
108
|
+
"""Performs a scan to check for YARA rules matches based on the file, either given by path or buffer.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
(List[Match]): A list of YARA matches.
|
|
112
|
+
"""
|
|
113
|
+
if filepath:
|
|
114
|
+
with open(filepath, "rb") as fp:
|
|
115
|
+
data = fp.read()
|
|
116
|
+
|
|
117
|
+
if isinstance(data, bytearray):
|
|
118
|
+
data = bytes(data)
|
|
119
|
+
|
|
120
|
+
return [Match(m, data) for m in self.scanner.scan(data).matching_rules]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def compile(source: str = None, sources: Dict[str, str] = None) -> Rules:
|
|
124
|
+
"""Compiles YARA rules from source or from sources.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
(Rules): a Rules object
|
|
128
|
+
"""
|
|
129
|
+
return Rules(source, sources)
|
maco/utils.py
CHANGED
|
@@ -280,8 +280,8 @@ def _install_required_packages(create_venv: bool, directories: List[str], python
|
|
|
280
280
|
|
|
281
281
|
install_command.extend(pyproject_command)
|
|
282
282
|
|
|
283
|
-
#
|
|
284
|
-
install_command.append("maco")
|
|
283
|
+
# Always require maco-extractor to be installed
|
|
284
|
+
install_command.append("maco-extractor")
|
|
285
285
|
logger.debug(f"Install command: {' '.join(install_command)} [{dir}]")
|
|
286
286
|
# this uses VIRTUAL_ENV to control usage of a virtual environment
|
|
287
287
|
p = subprocess.run(
|
|
@@ -8,28 +8,38 @@ demo_extractors/terminator.py,sha256=nxoZYRteYDQS7wp-aAsCaxCSJ9FSE54jPrW3fJpRVho
|
|
|
8
8
|
demo_extractors/complex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
demo_extractors/complex/complex.py,sha256=GYKmPOD8-fyVHxwjZb-3t1IghKVMuLtdUvCs5C5yPe0,2625
|
|
10
10
|
demo_extractors/complex/complex_utils.py,sha256=5kdMl-niSH9d-d3ChuItpmlPT4U-S9g-iyBZlR4tfmQ,296
|
|
11
|
+
extractor_setup/maco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
extractor_setup/maco/base_test.py,sha256=DrVE7vOazeLQpOQeIDwBYK1WtlmdJrRe50JOqP5t4Y0,3198
|
|
13
|
+
extractor_setup/maco/cli.py,sha256=nrSukAJAthbstZT3-lQNPz4zOOMcBhvfYQqLh_B5Jdk,9457
|
|
14
|
+
extractor_setup/maco/collector.py,sha256=R3zw-fUJBlwmcSqvkQ-PnoJdHfRm2V0JAOl7N8MTAbY,8240
|
|
15
|
+
extractor_setup/maco/exceptions.py,sha256=XBHUrs1kr1ZayPI9B_W-WejKgVmC8sWL_o4RL0b4DQE,745
|
|
16
|
+
extractor_setup/maco/extractor.py,sha256=s36aGcsXSc-9iCik6iihVt5G1a1DZUA7TquvWYQNwdE,2912
|
|
17
|
+
extractor_setup/maco/utils.py,sha256=yNm5CiHc9033ONX_gFwg9Lng5IYFujLDtw6FfiJkAao,23425
|
|
18
|
+
extractor_setup/maco/yara.py,sha256=y141t8NqDDXHY23uE1d6BDPeNmSuUuohR6Yr_LKa7GI,4067
|
|
19
|
+
extractor_setup/maco/model/__init__.py,sha256=ULdyHx8R5D2ICHZo3VoCk1YTlewTok36TYIpwx__pNY,45
|
|
20
|
+
extractor_setup/maco/model/model.py,sha256=DBHTmZXMzjpVq0s2mzZv3VCzPhwPnv7sH6u_QZCTcA4,24484
|
|
11
21
|
maco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
22
|
maco/base_test.py,sha256=DrVE7vOazeLQpOQeIDwBYK1WtlmdJrRe50JOqP5t4Y0,3198
|
|
13
23
|
maco/cli.py,sha256=nrSukAJAthbstZT3-lQNPz4zOOMcBhvfYQqLh_B5Jdk,9457
|
|
14
24
|
maco/collector.py,sha256=R3zw-fUJBlwmcSqvkQ-PnoJdHfRm2V0JAOl7N8MTAbY,8240
|
|
15
25
|
maco/exceptions.py,sha256=XBHUrs1kr1ZayPI9B_W-WejKgVmC8sWL_o4RL0b4DQE,745
|
|
16
26
|
maco/extractor.py,sha256=s36aGcsXSc-9iCik6iihVt5G1a1DZUA7TquvWYQNwdE,2912
|
|
17
|
-
maco/utils.py,sha256=
|
|
27
|
+
maco/utils.py,sha256=yNm5CiHc9033ONX_gFwg9Lng5IYFujLDtw6FfiJkAao,23425
|
|
18
28
|
maco/yara.py,sha256=y141t8NqDDXHY23uE1d6BDPeNmSuUuohR6Yr_LKa7GI,4067
|
|
19
29
|
maco/model/__init__.py,sha256=ULdyHx8R5D2ICHZo3VoCk1YTlewTok36TYIpwx__pNY,45
|
|
20
30
|
maco/model/model.py,sha256=DBHTmZXMzjpVq0s2mzZv3VCzPhwPnv7sH6u_QZCTcA4,24484
|
|
21
|
-
maco-1.2.
|
|
31
|
+
maco-1.2.18.dist-info/licenses/LICENSE.md,sha256=gMSjshPhXvV_F1qxmeNkKdBqGWkd__fEJf4glS504bM,1478
|
|
22
32
|
model_setup/maco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
33
|
model_setup/maco/base_test.py,sha256=DrVE7vOazeLQpOQeIDwBYK1WtlmdJrRe50JOqP5t4Y0,3198
|
|
24
34
|
model_setup/maco/cli.py,sha256=nrSukAJAthbstZT3-lQNPz4zOOMcBhvfYQqLh_B5Jdk,9457
|
|
25
35
|
model_setup/maco/collector.py,sha256=R3zw-fUJBlwmcSqvkQ-PnoJdHfRm2V0JAOl7N8MTAbY,8240
|
|
26
36
|
model_setup/maco/exceptions.py,sha256=XBHUrs1kr1ZayPI9B_W-WejKgVmC8sWL_o4RL0b4DQE,745
|
|
27
37
|
model_setup/maco/extractor.py,sha256=s36aGcsXSc-9iCik6iihVt5G1a1DZUA7TquvWYQNwdE,2912
|
|
28
|
-
model_setup/maco/utils.py,sha256=
|
|
38
|
+
model_setup/maco/utils.py,sha256=yNm5CiHc9033ONX_gFwg9Lng5IYFujLDtw6FfiJkAao,23425
|
|
29
39
|
model_setup/maco/yara.py,sha256=y141t8NqDDXHY23uE1d6BDPeNmSuUuohR6Yr_LKa7GI,4067
|
|
30
40
|
model_setup/maco/model/__init__.py,sha256=ULdyHx8R5D2ICHZo3VoCk1YTlewTok36TYIpwx__pNY,45
|
|
31
41
|
model_setup/maco/model/model.py,sha256=DBHTmZXMzjpVq0s2mzZv3VCzPhwPnv7sH6u_QZCTcA4,24484
|
|
32
|
-
pipelines/publish.yaml,sha256=
|
|
42
|
+
pipelines/publish.yaml,sha256=yjc3eqrI-LHLSfZ0DPtxwdfPDT0NI6LUA_zy61UxN_8,1654
|
|
33
43
|
pipelines/test.yaml,sha256=btJVI-R39UBeYosGu7TOpU6V9ogFW3FT3ROtWygQGQ0,1472
|
|
34
44
|
tests/data/example.txt.cart,sha256=j4ZdDnFNVq7lb-Qi4pY4evOXKQPKG-GSg-n-uEqPhV0,289
|
|
35
45
|
tests/data/trigger_complex.txt,sha256=uqnLSrnyDGCmXwuPmZ2s8vdhH0hJs8DxvyaW_tuYY24,64
|
|
@@ -42,8 +52,8 @@ tests/extractors/bob/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
|
42
52
|
tests/extractors/bob/bob.py,sha256=4fpqy_O6NDinJImghyW5OwYgnaB05aY4kgoIS_C3c_U,253
|
|
43
53
|
tests/extractors/import_rewriting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
54
|
tests/extractors/import_rewriting/importer.py,sha256=wqF1AG2zXXuj9EMt9qlDorab-UD0GYuFggtrCuz4sf0,289735
|
|
45
|
-
maco-1.2.
|
|
46
|
-
maco-1.2.
|
|
47
|
-
maco-1.2.
|
|
48
|
-
maco-1.2.
|
|
49
|
-
maco-1.2.
|
|
55
|
+
maco-1.2.18.dist-info/METADATA,sha256=citbYasnfKhc-PAxK7tLQt_Dc2LZRbhKn26ChD0PC3g,15310
|
|
56
|
+
maco-1.2.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
maco-1.2.18.dist-info/entry_points.txt,sha256=TpcwG1gedIg8Y7a9ZOv8aQpuwEUftCefDrAjzeP-o6U,39
|
|
58
|
+
maco-1.2.18.dist-info/top_level.txt,sha256=xiVS11ZoyN8ChHJQGpOzTH4ZyQ3YJe1qT3Yt4gcKGUk,65
|
|
59
|
+
maco-1.2.18.dist-info/RECORD,,
|
model_setup/maco/utils.py
CHANGED
|
@@ -280,8 +280,8 @@ def _install_required_packages(create_venv: bool, directories: List[str], python
|
|
|
280
280
|
|
|
281
281
|
install_command.extend(pyproject_command)
|
|
282
282
|
|
|
283
|
-
#
|
|
284
|
-
install_command.append("maco")
|
|
283
|
+
# Always require maco-extractor to be installed
|
|
284
|
+
install_command.append("maco-extractor")
|
|
285
285
|
logger.debug(f"Install command: {' '.join(install_command)} [{dir}]")
|
|
286
286
|
# this uses VIRTUAL_ENV to control usage of a virtual environment
|
|
287
287
|
p = subprocess.run(
|
pipelines/publish.yaml
CHANGED
|
@@ -12,34 +12,33 @@ pool:
|
|
|
12
12
|
vmImage: "ubuntu-22.04"
|
|
13
13
|
|
|
14
14
|
jobs:
|
|
15
|
-
- job: test
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
# - job: test
|
|
16
|
+
# displayName: Test
|
|
17
|
+
# strategy:
|
|
18
|
+
# matrix:
|
|
19
|
+
# Python38:
|
|
20
|
+
# python.version: '3.8'
|
|
21
|
+
# Python39:
|
|
22
|
+
# python.version: '3.9'
|
|
23
|
+
# Python310:
|
|
24
|
+
# python.version: '3.10'
|
|
25
|
+
# Python311:
|
|
26
|
+
# python.version: '3.11'
|
|
27
|
+
# Python312:
|
|
28
|
+
# python.version: '3.12'
|
|
29
|
+
# steps:
|
|
30
|
+
# - task: UsePythonVersion@0
|
|
31
|
+
# displayName: 'Use Python $(python.version)'
|
|
32
|
+
# inputs:
|
|
33
|
+
# versionSpec: '$(python.version)'
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
# - script: |
|
|
36
|
+
# set -x
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
# python -m pip install -U tox
|
|
39
|
+
# python -m tox -e py
|
|
40
40
|
|
|
41
41
|
- job: build_and_deploy
|
|
42
|
-
dependsOn: test
|
|
43
42
|
displayName: Build and Deploy
|
|
44
43
|
variables:
|
|
45
44
|
- group: deployment-information
|
|
@@ -64,6 +63,13 @@ jobs:
|
|
|
64
63
|
ls ../dist
|
|
65
64
|
displayName: Build (Model Only)
|
|
66
65
|
|
|
66
|
+
- script: |
|
|
67
|
+
set -x
|
|
68
|
+
cd extractor_setup
|
|
69
|
+
python -m build --outdir ../dist
|
|
70
|
+
ls ../dist
|
|
71
|
+
displayName: Build (Extractor Essentials)
|
|
72
|
+
|
|
67
73
|
- script: |
|
|
68
74
|
set -xv # Echo commands before they are run
|
|
69
75
|
sudo env "PATH=$PATH" python -m pip install --no-cache-dir twine
|
|
File without changes
|
|
File without changes
|
|
File without changes
|