maco 1.2.8__tar.gz → 1.2.10__tar.gz
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.
- {maco-1.2.8/maco.egg-info → maco-1.2.10}/PKG-INFO +3 -2
- {maco-1.2.8 → maco-1.2.10}/maco/collector.py +23 -3
- {maco-1.2.8 → maco-1.2.10}/maco/utils.py +9 -8
- {maco-1.2.8 → maco-1.2.10/maco.egg-info}/PKG-INFO +3 -2
- {maco-1.2.8 → maco-1.2.10}/maco.egg-info/requires.txt +1 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/collector.py +23 -3
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/utils.py +9 -8
- {maco-1.2.8 → maco-1.2.10}/requirements.txt +1 -0
- {maco-1.2.8 → maco-1.2.10}/.gitignore +0 -0
- {maco-1.2.8 → maco-1.2.10}/.vscode/settings.json +0 -0
- {maco-1.2.8 → maco-1.2.10}/LICENSE.md +0 -0
- {maco-1.2.8 → maco-1.2.10}/README.md +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/complex/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/complex/complex.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/complex/complex_utils.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/elfy.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/limit_other.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/nothing.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/requirements.txt +0 -0
- {maco-1.2.8 → maco-1.2.10}/demo_extractors/shared.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco/base_test.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco/cli.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco/extractor.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco/model/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco/model/model.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco/yara.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco.egg-info/SOURCES.txt +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco.egg-info/dependency_links.txt +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco.egg-info/entry_points.txt +0 -0
- {maco-1.2.8 → maco-1.2.10}/maco.egg-info/top_level.txt +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/LICENSE.md +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/README.md +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/base_test.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/cli.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/extractor.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/model/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/model/model.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/maco/yara.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/pyproject.toml +0 -0
- {maco-1.2.8 → maco-1.2.10}/model_setup/setup.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/pipelines/publish.yaml +0 -0
- {maco-1.2.8 → maco-1.2.10}/pipelines/test.yaml +0 -0
- {maco-1.2.8 → maco-1.2.10}/pyproject.toml +0 -0
- {maco-1.2.8 → maco-1.2.10}/setup.cfg +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/benchmark.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/data/example.txt.cart +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/data/trigger_complex.txt +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/data/trigger_complex.txt.cart +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/extractors/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/extractors/basic.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/extractors/basic_longer.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/extractors/bob/__init__.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/extractors/bob/bob.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/extractors/test_basic.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/pytest.ini +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/requirements.txt +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/test_base_test.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/test_cli.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/test_demo_extractors.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/test_detection.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/test_extractor.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/test_helpers.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tests/test_model.py +0 -0
- {maco-1.2.8 → maco-1.2.10}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: maco
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.10
|
|
4
4
|
Author: sl-govau
|
|
5
5
|
Maintainer: cccs-rs
|
|
6
6
|
License: MIT License
|
|
@@ -35,6 +35,7 @@ Requires-Dist: tomli>=1.1.0; python_version < "3.11"
|
|
|
35
35
|
Requires-Dist: uv
|
|
36
36
|
Requires-Dist: yara-python
|
|
37
37
|
Requires-Dist: yara-x==0.11.0
|
|
38
|
+
Requires-Dist: multiprocess>=0.70.17
|
|
38
39
|
|
|
39
40
|
# Maco - Malware config extractor framework
|
|
40
41
|
|
|
@@ -5,11 +5,11 @@ import logging
|
|
|
5
5
|
import logging.handlers
|
|
6
6
|
import os
|
|
7
7
|
import sys
|
|
8
|
-
from multiprocessing import Manager, Process, Queue
|
|
9
8
|
from tempfile import NamedTemporaryFile
|
|
10
9
|
from types import ModuleType
|
|
11
|
-
from typing import Any, BinaryIO, Dict, List, Union
|
|
10
|
+
from typing import Any, BinaryIO, Dict, List, TypedDict, Union
|
|
12
11
|
|
|
12
|
+
from multiprocess import Manager, Process, Queue
|
|
13
13
|
from pydantic import BaseModel
|
|
14
14
|
|
|
15
15
|
from maco import extractor, model, utils, yara
|
|
@@ -40,6 +40,26 @@ def _verify_response(resp: Union[BaseModel, dict]) -> Dict:
|
|
|
40
40
|
return resp.model_dump(exclude_defaults=True)
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
class ExtractorMetadata(TypedDict):
|
|
44
|
+
"""Extractor-supplied metadata."""
|
|
45
|
+
|
|
46
|
+
author: str
|
|
47
|
+
family: str
|
|
48
|
+
last_modified: str
|
|
49
|
+
sharing: str
|
|
50
|
+
description: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ExtractorRegistration(TypedDict):
|
|
54
|
+
"""Registration collected by the collector for a single extractor."""
|
|
55
|
+
|
|
56
|
+
venv: str
|
|
57
|
+
module_path: str
|
|
58
|
+
module_name: str
|
|
59
|
+
extractor_class: str
|
|
60
|
+
metadata: ExtractorMetadata
|
|
61
|
+
|
|
62
|
+
|
|
43
63
|
class Collector:
|
|
44
64
|
def __init__(
|
|
45
65
|
self,
|
|
@@ -60,7 +80,7 @@ class Collector:
|
|
|
60
80
|
|
|
61
81
|
path_extractors = os.path.realpath(path_extractors)
|
|
62
82
|
self.path: str = path_extractors
|
|
63
|
-
self.extractors: Dict[str,
|
|
83
|
+
self.extractors: Dict[str, ExtractorRegistration] = {}
|
|
64
84
|
|
|
65
85
|
with Manager() as manager:
|
|
66
86
|
extractors = manager.dict()
|
|
@@ -6,7 +6,6 @@ import inspect
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
import logging.handlers
|
|
9
|
-
import multiprocessing
|
|
10
9
|
import os
|
|
11
10
|
import re
|
|
12
11
|
import shutil
|
|
@@ -14,6 +13,8 @@ import subprocess
|
|
|
14
13
|
import sys
|
|
15
14
|
import tempfile
|
|
16
15
|
|
|
16
|
+
from multiprocess import Queue
|
|
17
|
+
|
|
17
18
|
from maco import yara
|
|
18
19
|
|
|
19
20
|
if sys.version_info >= (3, 11):
|
|
@@ -38,8 +39,8 @@ logger = logging.getLogger("maco.lib.utils")
|
|
|
38
39
|
|
|
39
40
|
VENV_DIRECTORY_NAME = ".venv"
|
|
40
41
|
|
|
41
|
-
RELATIVE_FROM_RE = re.compile(
|
|
42
|
-
RELATIVE_FROM_IMPORT_RE = re.compile(
|
|
42
|
+
RELATIVE_FROM_RE = re.compile(rb"from (\.+)")
|
|
43
|
+
RELATIVE_FROM_IMPORT_RE = re.compile(rb"from (\.+) import")
|
|
43
44
|
|
|
44
45
|
UV_BIN = find_uv_bin()
|
|
45
46
|
|
|
@@ -170,19 +171,19 @@ def scan_for_extractors(root_directory: str, scanner: yara.Rules, logger: Logger
|
|
|
170
171
|
# Scan Python file for potential extractors
|
|
171
172
|
if package:
|
|
172
173
|
# Inspect the contents and look for any relative import issues
|
|
173
|
-
with open(path, "
|
|
174
|
+
with open(path, "rb") as f:
|
|
174
175
|
data = f.read()
|
|
175
176
|
|
|
176
|
-
with open(path, "
|
|
177
|
+
with open(path, "wb") as f:
|
|
177
178
|
# Replace any relative importing with absolute
|
|
178
179
|
curr_dir = os.path.dirname(path)
|
|
179
180
|
split = curr_dir.split("/")[::-1]
|
|
180
181
|
for pattern in [RELATIVE_FROM_IMPORT_RE, RELATIVE_FROM_RE]:
|
|
181
182
|
for match in pattern.findall(data):
|
|
182
|
-
depth = match.count(".")
|
|
183
|
+
depth = match.count(b".")
|
|
183
184
|
abspath = ".".join(split[depth - 1 : split.index(package) + 1][::-1])
|
|
184
185
|
abspath += "." if pattern == RELATIVE_FROM_RE else ""
|
|
185
|
-
data = data.replace(f"from {match}", f"from {abspath}", 1)
|
|
186
|
+
data = data.replace(f"from {match.decode()}".encode(), f"from {abspath}".encode(), 1)
|
|
186
187
|
f.write(data)
|
|
187
188
|
|
|
188
189
|
if scanner.match(path):
|
|
@@ -390,7 +391,7 @@ def register_extractors(
|
|
|
390
391
|
break
|
|
391
392
|
|
|
392
393
|
|
|
393
|
-
def proxy_logging(queue:
|
|
394
|
+
def proxy_logging(queue: Queue, callback: Callable[[ModuleType, str], None], *args, **kwargs):
|
|
394
395
|
"""Ensures logging is set up correctly for a child process and then executes the callback."""
|
|
395
396
|
logger = logging.getLogger()
|
|
396
397
|
qh = logging.handlers.QueueHandler(queue)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: maco
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.10
|
|
4
4
|
Author: sl-govau
|
|
5
5
|
Maintainer: cccs-rs
|
|
6
6
|
License: MIT License
|
|
@@ -35,6 +35,7 @@ Requires-Dist: tomli>=1.1.0; python_version < "3.11"
|
|
|
35
35
|
Requires-Dist: uv
|
|
36
36
|
Requires-Dist: yara-python
|
|
37
37
|
Requires-Dist: yara-x==0.11.0
|
|
38
|
+
Requires-Dist: multiprocess>=0.70.17
|
|
38
39
|
|
|
39
40
|
# Maco - Malware config extractor framework
|
|
40
41
|
|
|
@@ -5,11 +5,11 @@ import logging
|
|
|
5
5
|
import logging.handlers
|
|
6
6
|
import os
|
|
7
7
|
import sys
|
|
8
|
-
from multiprocessing import Manager, Process, Queue
|
|
9
8
|
from tempfile import NamedTemporaryFile
|
|
10
9
|
from types import ModuleType
|
|
11
|
-
from typing import Any, BinaryIO, Dict, List, Union
|
|
10
|
+
from typing import Any, BinaryIO, Dict, List, TypedDict, Union
|
|
12
11
|
|
|
12
|
+
from multiprocess import Manager, Process, Queue
|
|
13
13
|
from pydantic import BaseModel
|
|
14
14
|
|
|
15
15
|
from maco import extractor, model, utils, yara
|
|
@@ -40,6 +40,26 @@ def _verify_response(resp: Union[BaseModel, dict]) -> Dict:
|
|
|
40
40
|
return resp.model_dump(exclude_defaults=True)
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
class ExtractorMetadata(TypedDict):
|
|
44
|
+
"""Extractor-supplied metadata."""
|
|
45
|
+
|
|
46
|
+
author: str
|
|
47
|
+
family: str
|
|
48
|
+
last_modified: str
|
|
49
|
+
sharing: str
|
|
50
|
+
description: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ExtractorRegistration(TypedDict):
|
|
54
|
+
"""Registration collected by the collector for a single extractor."""
|
|
55
|
+
|
|
56
|
+
venv: str
|
|
57
|
+
module_path: str
|
|
58
|
+
module_name: str
|
|
59
|
+
extractor_class: str
|
|
60
|
+
metadata: ExtractorMetadata
|
|
61
|
+
|
|
62
|
+
|
|
43
63
|
class Collector:
|
|
44
64
|
def __init__(
|
|
45
65
|
self,
|
|
@@ -60,7 +80,7 @@ class Collector:
|
|
|
60
80
|
|
|
61
81
|
path_extractors = os.path.realpath(path_extractors)
|
|
62
82
|
self.path: str = path_extractors
|
|
63
|
-
self.extractors: Dict[str,
|
|
83
|
+
self.extractors: Dict[str, ExtractorRegistration] = {}
|
|
64
84
|
|
|
65
85
|
with Manager() as manager:
|
|
66
86
|
extractors = manager.dict()
|
|
@@ -6,7 +6,6 @@ import inspect
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
import logging.handlers
|
|
9
|
-
import multiprocessing
|
|
10
9
|
import os
|
|
11
10
|
import re
|
|
12
11
|
import shutil
|
|
@@ -14,6 +13,8 @@ import subprocess
|
|
|
14
13
|
import sys
|
|
15
14
|
import tempfile
|
|
16
15
|
|
|
16
|
+
from multiprocess import Queue
|
|
17
|
+
|
|
17
18
|
from maco import yara
|
|
18
19
|
|
|
19
20
|
if sys.version_info >= (3, 11):
|
|
@@ -38,8 +39,8 @@ logger = logging.getLogger("maco.lib.utils")
|
|
|
38
39
|
|
|
39
40
|
VENV_DIRECTORY_NAME = ".venv"
|
|
40
41
|
|
|
41
|
-
RELATIVE_FROM_RE = re.compile(
|
|
42
|
-
RELATIVE_FROM_IMPORT_RE = re.compile(
|
|
42
|
+
RELATIVE_FROM_RE = re.compile(rb"from (\.+)")
|
|
43
|
+
RELATIVE_FROM_IMPORT_RE = re.compile(rb"from (\.+) import")
|
|
43
44
|
|
|
44
45
|
UV_BIN = find_uv_bin()
|
|
45
46
|
|
|
@@ -170,19 +171,19 @@ def scan_for_extractors(root_directory: str, scanner: yara.Rules, logger: Logger
|
|
|
170
171
|
# Scan Python file for potential extractors
|
|
171
172
|
if package:
|
|
172
173
|
# Inspect the contents and look for any relative import issues
|
|
173
|
-
with open(path, "
|
|
174
|
+
with open(path, "rb") as f:
|
|
174
175
|
data = f.read()
|
|
175
176
|
|
|
176
|
-
with open(path, "
|
|
177
|
+
with open(path, "wb") as f:
|
|
177
178
|
# Replace any relative importing with absolute
|
|
178
179
|
curr_dir = os.path.dirname(path)
|
|
179
180
|
split = curr_dir.split("/")[::-1]
|
|
180
181
|
for pattern in [RELATIVE_FROM_IMPORT_RE, RELATIVE_FROM_RE]:
|
|
181
182
|
for match in pattern.findall(data):
|
|
182
|
-
depth = match.count(".")
|
|
183
|
+
depth = match.count(b".")
|
|
183
184
|
abspath = ".".join(split[depth - 1 : split.index(package) + 1][::-1])
|
|
184
185
|
abspath += "." if pattern == RELATIVE_FROM_RE else ""
|
|
185
|
-
data = data.replace(f"from {match}", f"from {abspath}", 1)
|
|
186
|
+
data = data.replace(f"from {match.decode()}".encode(), f"from {abspath}".encode(), 1)
|
|
186
187
|
f.write(data)
|
|
187
188
|
|
|
188
189
|
if scanner.match(path):
|
|
@@ -390,7 +391,7 @@ def register_extractors(
|
|
|
390
391
|
break
|
|
391
392
|
|
|
392
393
|
|
|
393
|
-
def proxy_logging(queue:
|
|
394
|
+
def proxy_logging(queue: Queue, callback: Callable[[ModuleType, str], None], *args, **kwargs):
|
|
394
395
|
"""Ensures logging is set up correctly for a child process and then executes the callback."""
|
|
395
396
|
logger = logging.getLogger()
|
|
396
397
|
qh = logging.handlers.QueueHandler(queue)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|