maco 1.2.17__py3-none-any.whl → 1.2.19__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 +221 -0
- extractor_setup/maco/exceptions.py +33 -0
- extractor_setup/maco/extractor.py +71 -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/collector.py +1 -0
- maco/extractor.py +2 -1
- maco/utils.py +2 -2
- {maco-1.2.17.dist-info → maco-1.2.19.dist-info}/METADATA +2 -1
- {maco-1.2.17.dist-info → maco-1.2.19.dist-info}/RECORD +23 -13
- {maco-1.2.17.dist-info → maco-1.2.19.dist-info}/top_level.txt +1 -0
- model_setup/maco/collector.py +1 -0
- model_setup/maco/extractor.py +2 -1
- model_setup/maco/utils.py +2 -2
- pipelines/publish.yaml +7 -0
- {maco-1.2.17.dist-info → maco-1.2.19.dist-info}/WHEEL +0 -0
- {maco-1.2.17.dist-info → maco-1.2.19.dist-info}/entry_points.txt +0 -0
- {maco-1.2.17.dist-info → maco-1.2.19.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/collector.py
CHANGED
maco/extractor.py
CHANGED
|
@@ -25,7 +25,8 @@ class Extractor:
|
|
|
25
25
|
family: Union[str, List[str]] = None # family or families of malware that is detected by the extractor
|
|
26
26
|
author: str = None # author of the extractor (name@organisation)
|
|
27
27
|
last_modified: str = None # last modified date (YYYY-MM-DD)
|
|
28
|
-
sharing: str = "TLP:
|
|
28
|
+
sharing: str = "TLP:CLEAR" # who can this be shared with?
|
|
29
|
+
result_sharing: str = sharing # who can the results be shared with? (defaults to sharing)
|
|
29
30
|
yara_rule: str = None # yara rule that we filter inputs with
|
|
30
31
|
reference: str = None # link to malware report or other reference information
|
|
31
32
|
logger: logging.Logger = None # logger for use when debugging
|
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=I0Nidf4-xcvoe6X0bbCsAXjr66iPf00JDO6ocKkaZLc,8309
|
|
15
|
+
extractor_setup/maco/exceptions.py,sha256=XBHUrs1kr1ZayPI9B_W-WejKgVmC8sWL_o4RL0b4DQE,745
|
|
16
|
+
extractor_setup/maco/extractor.py,sha256=nqIfUcrc_l57FicKZc6HLtN223-_zkYWL1AYMy1WAmA,3007
|
|
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
|
-
maco/collector.py,sha256=
|
|
24
|
+
maco/collector.py,sha256=I0Nidf4-xcvoe6X0bbCsAXjr66iPf00JDO6ocKkaZLc,8309
|
|
15
25
|
maco/exceptions.py,sha256=XBHUrs1kr1ZayPI9B_W-WejKgVmC8sWL_o4RL0b4DQE,745
|
|
16
|
-
maco/extractor.py,sha256=
|
|
17
|
-
maco/utils.py,sha256=
|
|
26
|
+
maco/extractor.py,sha256=nqIfUcrc_l57FicKZc6HLtN223-_zkYWL1AYMy1WAmA,3007
|
|
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.19.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
|
-
model_setup/maco/collector.py,sha256=
|
|
35
|
+
model_setup/maco/collector.py,sha256=I0Nidf4-xcvoe6X0bbCsAXjr66iPf00JDO6ocKkaZLc,8309
|
|
26
36
|
model_setup/maco/exceptions.py,sha256=XBHUrs1kr1ZayPI9B_W-WejKgVmC8sWL_o4RL0b4DQE,745
|
|
27
|
-
model_setup/maco/extractor.py,sha256=
|
|
28
|
-
model_setup/maco/utils.py,sha256=
|
|
37
|
+
model_setup/maco/extractor.py,sha256=nqIfUcrc_l57FicKZc6HLtN223-_zkYWL1AYMy1WAmA,3007
|
|
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=BfsbDsg2ijtXF8lhRUjzkenw3zi2mL7ESNv3KuC1cVE,1626
|
|
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.19.dist-info/METADATA,sha256=bcX2cXg2jbw6epAkczHoP9WOlcRTKcFtutfrVAc3mIg,15310
|
|
56
|
+
maco-1.2.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
maco-1.2.19.dist-info/entry_points.txt,sha256=TpcwG1gedIg8Y7a9ZOv8aQpuwEUftCefDrAjzeP-o6U,39
|
|
58
|
+
maco-1.2.19.dist-info/top_level.txt,sha256=xiVS11ZoyN8ChHJQGpOzTH4ZyQ3YJe1qT3Yt4gcKGUk,65
|
|
59
|
+
maco-1.2.19.dist-info/RECORD,,
|
model_setup/maco/collector.py
CHANGED
model_setup/maco/extractor.py
CHANGED
|
@@ -25,7 +25,8 @@ class Extractor:
|
|
|
25
25
|
family: Union[str, List[str]] = None # family or families of malware that is detected by the extractor
|
|
26
26
|
author: str = None # author of the extractor (name@organisation)
|
|
27
27
|
last_modified: str = None # last modified date (YYYY-MM-DD)
|
|
28
|
-
sharing: str = "TLP:
|
|
28
|
+
sharing: str = "TLP:CLEAR" # who can this be shared with?
|
|
29
|
+
result_sharing: str = sharing # who can the results be shared with? (defaults to sharing)
|
|
29
30
|
yara_rule: str = None # yara rule that we filter inputs with
|
|
30
31
|
reference: str = None # link to malware report or other reference information
|
|
31
32
|
logger: logging.Logger = None # logger for use when debugging
|
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
|
@@ -64,6 +64,13 @@ jobs:
|
|
|
64
64
|
ls ../dist
|
|
65
65
|
displayName: Build (Model Only)
|
|
66
66
|
|
|
67
|
+
- script: |
|
|
68
|
+
set -x
|
|
69
|
+
cd extractor_setup
|
|
70
|
+
python -m build --outdir ../dist
|
|
71
|
+
ls ../dist
|
|
72
|
+
displayName: Build (Extractor Essentials)
|
|
73
|
+
|
|
67
74
|
- script: |
|
|
68
75
|
set -xv # Echo commands before they are run
|
|
69
76
|
sudo env "PATH=$PATH" python -m pip install --no-cache-dir twine
|
|
File without changes
|
|
File without changes
|
|
File without changes
|