maco 1.2.5__py3-none-any.whl → 1.2.7__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.
demo_extractors/elfy.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from io import BytesIO
2
- from typing import Dict, List, Optional
2
+ from typing import List, Optional
3
3
 
4
4
  from maco import extractor, model, yara
5
5
 
@@ -1,5 +1,5 @@
1
1
  from io import BytesIO
2
- from typing import Dict, List, Optional
2
+ from typing import List, Optional
3
3
 
4
4
  from demo_extractors import shared
5
5
  from maco import extractor, model, yara
@@ -27,6 +27,10 @@ class LimitOther(extractor.Extractor):
27
27
  # the tests that do direct importing
28
28
  import httpx
29
29
 
30
+ # use httpx so it doesn't get deleted by auto linter
31
+ if not httpx.__name__:
32
+ raise Exception("wow I really want to use this library in a useful way")
33
+
30
34
  # use a custom model that inherits from ExtractorModel
31
35
  # this model defines what can go in the 'other' dict
32
36
  tmp = shared.MyCustomModel(family="specify_other")
@@ -1,5 +1,5 @@
1
1
  from io import BytesIO
2
- from typing import Dict, List, Optional
2
+ from typing import List, Optional
3
3
 
4
4
  from maco import extractor, model, yara
5
5
 
maco/base_test.py CHANGED
@@ -32,7 +32,7 @@ class BaseTest(unittest.TestCase):
32
32
  # I recommend something like os.path.join(__file__, "../../extractors")
33
33
  # if your extractors are in a folder 'extractors' next to a folder of tests
34
34
  path: str = None
35
- create_venv: bool=False
35
+ create_venv: bool = False
36
36
 
37
37
  @classmethod
38
38
  def setUpClass(cls) -> None:
maco/cli.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """CLI example of how extractors can be executed."""
2
+
2
3
  import argparse
3
4
  import base64
4
5
  import binascii
@@ -150,6 +151,7 @@ def process_filesystem(
150
151
  logger.info(f"{num_analysed} analysed, {num_hits} hits, {num_extracted} extracted")
151
152
  return num_analysed, num_hits, num_extracted
152
153
 
154
+
153
155
  def main():
154
156
  parser = argparse.ArgumentParser(description="Run extractors over samples.")
155
157
  parser.add_argument("extractors", type=str, help="path to extractors")
@@ -165,7 +167,8 @@ def main():
165
167
  parser.add_argument(
166
168
  "--base64",
167
169
  action="store_true",
168
- help="Include base64 encoded binary data in output (can be large, consider printing to file rather than console)",
170
+ help="Include base64 encoded binary data in output "
171
+ "(can be large, consider printing to file rather than console)",
169
172
  )
170
173
  parser.add_argument("--logfile", type=str, help="file to log output")
171
174
  parser.add_argument("--include", type=str, help="comma separated extractors to run")
@@ -179,7 +182,9 @@ def main():
179
182
  parser.add_argument(
180
183
  "--create_venv",
181
184
  action="store_true",
182
- help="Creates venvs for every requirements.txt found (only applies when extractor path is a directory). This runs much slower than the alternative but may be necessary when there are many extractors with conflicting dependencies.",
185
+ help="Creates venvs for every requirements.txt found (only applies when extractor path is a directory). "
186
+ "This runs much slower than the alternative but may be necessary "
187
+ "when there are many extractors with conflicting dependencies.",
183
188
  )
184
189
  args = parser.parse_args()
185
190
  inc = args.include.split(",") if args.include else []
@@ -225,7 +230,7 @@ def main():
225
230
  pretty=args.pretty,
226
231
  force=args.force,
227
232
  include_base64=args.base64,
228
- create_venv=args.create_venv
233
+ create_venv=args.create_venv,
229
234
  )
230
235
 
231
236
 
maco/collector.py CHANGED
@@ -4,6 +4,7 @@ import inspect
4
4
  import logging
5
5
  import logging.handlers
6
6
  import os
7
+ import sys
7
8
  from multiprocessing import Manager, Process, Queue
8
9
  from tempfile import NamedTemporaryFile
9
10
  from types import ModuleType
@@ -48,6 +49,15 @@ class Collector:
48
49
  create_venv: bool = False,
49
50
  ):
50
51
  """Discover and load extractors from file system."""
52
+ # maco requires the extractor to be imported directly, so ensure they are available on the path
53
+ full_path_extractors = os.path.abspath(path_extractors)
54
+ full_path_above_extractors = os.path.dirname(full_path_extractors)
55
+ # Modify the PATH so we can recognize this new package on import
56
+ if full_path_extractors not in sys.path:
57
+ sys.path.insert(1, full_path_extractors)
58
+ if full_path_above_extractors not in sys.path:
59
+ sys.path.insert(1, full_path_above_extractors)
60
+
51
61
  path_extractors = os.path.realpath(path_extractors)
52
62
  self.path: str = path_extractors
53
63
  self.extractors: Dict[str, Dict[str, str]] = {}
@@ -89,7 +99,7 @@ class Collector:
89
99
 
90
100
  # multiprocess logging is awkward - set up a queue to ensure we can log
91
101
  logging_queue = Queue()
92
- queue_handler = logging.handlers.QueueListener(logging_queue,*logging.getLogger().handlers)
102
+ queue_handler = logging.handlers.QueueListener(logging_queue, *logging.getLogger().handlers)
93
103
  queue_handler.start()
94
104
 
95
105
  # Find the extractors within the given directory
maco/model/__init__.py CHANGED
@@ -1 +1 @@
1
- from maco.model.model import *
1
+ from maco.model.model import * # noqa: F403
maco/model/model.py CHANGED
@@ -59,31 +59,48 @@ class CategoryEnum(str, Enum):
59
59
  # Malware related to an Advanced Persistent Threat (APT) group.
60
60
  apt = "apt"
61
61
 
62
- # A backdoor Trojan gives malicious users remote control over the infected computer. They enable the author to do anything they wish on the infected computer including sending, receiving, launching and deleting files, displaying data and rebooting the computer. Backdoor Trojans are often used to unite a group of victim computers to form a botnet or zombie network that can be used for criminal purposes.
62
+ # A backdoor Trojan gives malicious users remote control over the infected computer.
63
+ # They enable the author to do anything they wish on the infected computer including
64
+ # sending, receiving, launching and deleting files, displaying data and rebooting the computer.
65
+ # Backdoor Trojans are often used to unite a group of victim computers to form a botnet or
66
+ # zombie network that can be used for criminal purposes.
63
67
  backdoor = "backdoor"
64
68
 
65
- # Trojan Banker programs are designed to steal your account data for online banking systems, e-payment systems and credit or debit cards.
69
+ # Trojan Banker programs are designed to steal your account data for online banking systems,
70
+ # e-payment systems and credit or debit cards.
66
71
  banker = "banker"
67
72
 
68
- # A malware variant that modifies the boot sectors of a hard drive, including the Master Boot Record (MBR) and Volume Boot Record (VBR).
73
+ # A malware variant that modifies the boot sectors of a hard drive, including the Master Boot Record (MBR)
74
+ # and Volume Boot Record (VBR).
69
75
  bootkit = "bootkit"
70
76
 
71
- # A malicious bot is self-propagating malware designed to infect a host and connect back to a central server or servers that act as a command and control (C&C) center for an entire network of compromised devices, or botnet.
77
+ # A malicious bot is self-propagating malware designed to infect a host and connect back to a central server
78
+ # or servers that act as a command and control (C&C) center for an entire network of compromised devices,
79
+ # or botnet.
72
80
  bot = "bot"
73
81
 
74
- # A browser hijacker is defined as a form of unwanted software that modifies a web browser's settings without the user's permission. The result is the placement of unwanted advertising into the browser, and possibly the replacement of an existing home page or search page with the hijacker page.
82
+ # A browser hijacker is defined as a form of unwanted software that modifies a web browser's settings without
83
+ # the user's permission. The result is the placement of unwanted advertising into the browser,
84
+ # and possibly the replacement of an existing home page or search page with the hijacker page.
75
85
  browser_hijacker = "browser_hijacker"
76
86
 
77
- # Trojan bruteforcer are trying to brute force website in order to achieve something else (EX: Finding WordPress websites with default credentials).
87
+ # Trojan bruteforcer are trying to brute force website in order to achieve something else
88
+ # (EX: Finding WordPress websites with default credentials).
78
89
  bruteforcer = "bruteforcer"
79
90
 
80
- # A type of trojan that can use your PC to 'click' on websites or applications. They are usually used to make money for a malicious hacker by clicking on online advertisements and making it look like the website gets more traffic than it does. They can also be used to skew online polls, install programs on your PC, or make unwanted software appear more popular than it is.
91
+ # A type of trojan that can use your PC to 'click' on websites or applications.
92
+ # They are usually used to make money for a malicious hacker by clicking on online advertisements
93
+ # and making it look like the website gets more traffic than it does.
94
+ # They can also be used to skew online polls, install programs on your PC, or make unwanted software
95
+ # appear more popular than it is.
81
96
  clickfraud = "clickfraud"
82
97
 
83
98
  # Cryptocurrency mining malware.
84
99
  cryptominer = "cryptominer"
85
100
 
86
- # These programs conduct DoS (Denial of Service) attacks against a targeted web address. By sending multiple requests from your computer and several other infected computers, the attack can overwhelm the target address leading to a denial of service.
101
+ # These programs conduct DoS (Denial of Service) attacks against a targeted web address.
102
+ # By sending multiple requests from your computer and several other infected computers,
103
+ # the attack can overwhelm the target address leading to a denial of service.
87
104
  ddos = "ddos"
88
105
 
89
106
  # Trojan Downloaders can download and install new versions of malicious programs in the target system.
@@ -92,49 +109,66 @@ class CategoryEnum(str, Enum):
92
109
  # These programs are used by hackers in order to install malware or to prevent the detection of malicious programs.
93
110
  dropper = "dropper"
94
111
 
95
- # Exploit kits are programs that contain data or code that takes advantage of a vulnerability within an application that is running in the target system.
112
+ # Exploit kits are programs that contain data or code that takes advantage of a vulnerability
113
+ # within an application that is running in the target system.
96
114
  exploitkit = "exploitkit"
97
115
 
98
- # Trojan FakeAV programs simulate the activity of antivirus software. They are designed to extort money in return for the detection and removal of threat, even though the threats that they report are actually non-existent.
116
+ # Trojan FakeAV programs simulate the activity of antivirus software.
117
+ # They are designed to extort money in return for the detection and removal of threat, even though the
118
+ # threats that they report are actually non-existent.
99
119
  fakeav = "fakeav"
100
120
 
101
121
  # A type of tool that can be used to allow and maintain unauthorized access to your PC.
102
122
  hacktool = "hacktool"
103
123
 
104
- # A program that collects your personal information, such as your browsing history, and uses it without adequate consent.
124
+ # A program that collects your personal information, such as your browsing history,
125
+ # and uses it without adequate consent.
105
126
  infostealer = "infostealer"
106
127
 
107
- # A keylogger monitors and logs every keystroke it can identify. Once installed, the virus either keeps track of all the keys and stores the information locally, after which the hacker needs physical access to the computer to retrieve the information, or the logs are sent over the internet back to the hacker.
128
+ # A keylogger monitors and logs every keystroke it can identify.
129
+ # Once installed, the virus either keeps track of all the keys and stores the information locally,
130
+ # after which the hacker needs physical access to the computer to retrieve the information,
131
+ # or the logs are sent over the internet back to the hacker.
108
132
  keylogger = "keylogger"
109
133
 
110
134
  # A program that loads another application / memory space.
111
135
  loader = "loader"
112
136
 
113
- # A type of malware that hides its code and purpose to make it more difficult for security software to detect or remove it.
137
+ # A type of malware that hides its code and purpose to make it more difficult for
138
+ # security software to detect or remove it.
114
139
  obfuscator = "obfuscator"
115
140
 
116
- # Point-of-sale malware is usually a type of malware that is used by cybercriminals to target point of sale (POS) and payment terminals with the intent to obtain credit card and debit card information.
141
+ # Point-of-sale malware is usually a type of malware that is used by cybercriminals to target point of sale (POS)
142
+ # and payment terminals with the intent to obtain credit card and debit card information.
117
143
  pos = "pos"
118
144
 
119
- # This type of trojan allows unauthorized parties to use the infected computer as a proxy server to access the Internet anonymously.
145
+ # This type of trojan allows unauthorized parties to use the infected computer as a proxy server
146
+ # to access the Internet anonymously.
120
147
  proxy = "proxy"
121
148
 
122
149
  # A program that can be used by a remote hacker to gain access and control of an infected machine.
123
150
  rat = "rat"
124
151
 
125
- # This type of malware can modify data in the target computer so the operating system will stop running correctly or the data is no longer accessible. The criminal will only restore the computer state or data after a ransom is paid to them (mostly using cryptocurrency).
152
+ # This type of malware can modify data in the target computer so the operating system
153
+ # will stop running correctly or the data is no longer accessible.
154
+ # The criminal will only restore the computer state or data after a ransom is paid to them
155
+ # (mostly using cryptocurrency).
126
156
  ransomware = "ransomware"
127
157
 
128
158
  # A reverse proxy is a server that receives requests from the internet and forwards them to a small set of servers.
129
159
  reverse_proxy = "reverse_proxy"
130
160
 
131
- # Rootkits are designed to conceal certain objects or activities in the system. Often their main purpose is to prevent malicious programs being detected in order to extend the period in which programs can run on an infected computer.
161
+ # Rootkits are designed to conceal certain objects or activities in the system.
162
+ # Often their main purpose is to prevent malicious programs being detected
163
+ # in order to extend the period in which programs can run on an infected computer.
132
164
  rootkit = "rootkit"
133
165
 
134
- # This type of malware scan the internet / network(s) / system(s) / service(s) to collect information. That information could be used later to perpetuate an cyber attack.
166
+ # This type of malware scan the internet / network(s) / system(s) / service(s) to collect information.
167
+ # That information could be used later to perpetuate an cyber attack.
135
168
  scanner = "scanner"
136
169
 
137
- # Scareware is a form of malware which uses social engineering to cause shock, anxiety, or the perception of a threat in order to manipulate users into buying unwanted software.
170
+ # Scareware is a form of malware which uses social engineering to cause shock, anxiety,
171
+ # or the perception of a threat in order to manipulate users into buying unwanted software.
138
172
  scareware = "scareware"
139
173
 
140
174
  # Malware that is sending spam.
maco/utils.py CHANGED
@@ -46,6 +46,7 @@ UV_BIN = find_uv_bin()
46
46
  PIP_CMD = f"{UV_BIN} pip"
47
47
  VENV_CREATE_CMD = f"{UV_BIN} venv"
48
48
 
49
+
49
50
  class Base64Decoder(json.JSONDecoder):
50
51
  def __init__(self, *args, **kwargs):
51
52
  json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)
@@ -179,11 +180,9 @@ def scan_for_extractors(root_directory: str, scanner: yara.Rules, logger: Logger
179
180
  for pattern in [RELATIVE_FROM_IMPORT_RE, RELATIVE_FROM_RE]:
180
181
  for match in pattern.findall(data):
181
182
  depth = match.count(".")
182
- data = data.replace(
183
- f"from {match}",
184
- f"from {'.'.join(split[depth - 1 : split.index(package) + 1][::-1])}{'.' if pattern == RELATIVE_FROM_RE else ''}",
185
- 1,
186
- )
183
+ abspath = ".".join(split[depth - 1 : split.index(package) + 1][::-1])
184
+ abspath += "." if pattern == RELATIVE_FROM_RE else ""
185
+ data = data.replace(f"from {match}", f"from {abspath}", 1)
187
186
  f.write(data)
188
187
 
189
188
  if scanner.match(path):
@@ -222,7 +221,12 @@ def _install_required_packages(create_venv: bool, directories: List[str], python
222
221
  subprocess.run(cmd.split(" ") + [venv_path], capture_output=True, env=env)
223
222
 
224
223
  # Install/Update the packages in the environment
225
- install_command = PIP_CMD.split(" ") + ["install", "-U"]
224
+ install_command = PIP_CMD.split(" ") + ["install"]
225
+ # When running locally, only install packages to required spec.
226
+ # This prevents issues during maco development and building extractors against local libraries.
227
+ if create_venv:
228
+ # when running in custom virtual environment, always upgrade packages.
229
+ install_command.append("-U")
226
230
 
227
231
  # Update the pip install command depending on where the dependencies are coming from
228
232
  if "requirements.txt" in req_files:
@@ -307,8 +311,10 @@ def register_extractors(
307
311
  parent_directory = os.path.dirname(current_directory)
308
312
  if venvs and package_name in sys.modules:
309
313
  # this may happen as part of testing if some part of the extractor code was directly imported
310
- logger.warning(f"Looks like {package_name} is already loaded. "
311
- "If your maco extractor overlaps an existing package name this could cause problems.")
314
+ logger.warning(
315
+ f"Looks like {package_name} is already loaded. "
316
+ "If your maco extractor overlaps an existing package name this could cause problems."
317
+ )
312
318
 
313
319
  try:
314
320
  # Modify the PATH so we can recognize this new package on import
@@ -383,6 +389,7 @@ def register_extractors(
383
389
  # We were able to find all the extractor files
384
390
  break
385
391
 
392
+
386
393
  def proxy_logging(queue: multiprocessing.Queue, callback: Callable[[ModuleType, str], None], *args, **kwargs):
387
394
  """Ensures logging is set up correctly for a child process and then executes the callback."""
388
395
  logger = logging.getLogger()
@@ -391,6 +398,7 @@ def proxy_logging(queue: multiprocessing.Queue, callback: Callable[[ModuleType,
391
398
  logger.addHandler(qh)
392
399
  callback(*args, **kwargs, logger=logger)
393
400
 
401
+
394
402
  def import_extractors(
395
403
  extractor_module_callback: Callable[[ModuleType, str], bool],
396
404
  *,
@@ -399,14 +407,24 @@ def import_extractors(
399
407
  create_venv: bool,
400
408
  logger: Logger,
401
409
  python_version: str = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
410
+ skip_install: bool = False,
402
411
  ):
403
412
  extractor_dirs, extractor_files = scan_for_extractors(root_directory, scanner, logger)
404
413
 
405
414
  logger.info(f"Extractor files found based on scanner ({len(extractor_files)}).")
406
415
  logger.debug(extractor_files)
407
416
 
408
- # Install packages into the current environment or dynamically created virtual environments
409
- venvs = _install_required_packages(create_venv, extractor_dirs, python_version, logger)
417
+ if not skip_install:
418
+ # Install packages into the current environment or dynamically created virtual environments
419
+ venvs = _install_required_packages(create_venv, extractor_dirs, python_version, logger)
420
+ else:
421
+ # Look for pre-existing virtual environments, if any
422
+ logger.info("Checking for pre-existing virtual environment(s)..")
423
+ venvs = [
424
+ os.path.join(root, VENV_DIRECTORY_NAME)
425
+ for root, dirs, _ in os.walk(root_directory)
426
+ if VENV_DIRECTORY_NAME in dirs
427
+ ]
410
428
 
411
429
  # With the environment prepared, we can now hunt for the extractors and register them
412
430
  logger.info("Registering extractors..")
@@ -416,6 +434,7 @@ def import_extractors(
416
434
  # holds cached extractors when not running in venv mode
417
435
  _loaded_extractors: Dict[str, Extractor] = {}
418
436
 
437
+
419
438
  def run_extractor(
420
439
  sample_path,
421
440
  module_name,
@@ -438,7 +457,7 @@ def run_extractor(
438
457
  extractor = _loaded_extractors[key]
439
458
  if extractor.yara_compiled:
440
459
  matches = extractor.yara_compiled.match(sample_path)
441
- loaded = extractor.run(open(sample_path, 'rb'), matches=matches)
460
+ loaded = extractor.run(open(sample_path, "rb"), matches=matches)
442
461
  else:
443
462
  # execute extractor in child process with separate virtual environment
444
463
  # Write temporary script in the same directory as extractor to resolve relative imports
@@ -477,7 +496,7 @@ def run_extractor(
477
496
  try:
478
497
  # Load results and return them
479
498
  output.seek(0)
480
- loaded = json.load(output, cls=json_decoder)
499
+ loaded = json.load(output, cls=json_decoder)
481
500
  except Exception as e:
482
501
  # If there was an error raised during runtime, then propagate
483
502
  delim = f'File "{module_path}"'
maco/yara.py CHANGED
@@ -3,7 +3,6 @@ from collections import namedtuple
3
3
  from itertools import cycle
4
4
  from typing import Dict
5
5
 
6
- import yara
7
6
  import yara_x
8
7
 
9
8
  RULE_ID_RE = re.compile("(\w+)? ?rule (\w+)")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: maco
3
- Version: 1.2.5
3
+ Version: 1.2.7
4
4
  Author: sl-govau
5
5
  Maintainer: cccs-rs
6
6
  License: MIT License
@@ -38,7 +38,7 @@ Requires-Dist: yara-x==0.11.0
38
38
 
39
39
  # Maco - Malware config extractor framework
40
40
 
41
- ## Maco is a framework for ***ma***lware ***co***nfig extractors.
41
+ ## Maco is a framework for <ins>ma</ins>lware <ins>co</ins>nfig extractors.
42
42
 
43
43
  It aims to solve two problems:
44
44
 
@@ -272,3 +272,15 @@ run Complex extractor from rules ['ComplexAlt']
272
272
  The demo extractors are designed to trigger when run over the '`demo_extractors`' folder.
273
273
 
274
274
  e.g. `maco demo_extractors demo_extractors`
275
+
276
+ # Contributions
277
+
278
+ Please use ruff to format and lint PRs. This may be the cause of PR test failures.
279
+
280
+ Ruff will attempt to fix most issues, but some may require manual resolution.
281
+
282
+ ```
283
+ pip install ruff
284
+ ruff format
285
+ ruff check --fix
286
+ ```
@@ -0,0 +1,44 @@
1
+ demo_extractors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ demo_extractors/elfy.py,sha256=Jo_GKExCeFOKGENJnNM_9ONfJO7LQFucCNz0ryTAo9U,765
3
+ demo_extractors/limit_other.py,sha256=BWjeyOxB75kw4eRla5zvSzdcXtELOS8R6hc71rLPh1s,1295
4
+ demo_extractors/nothing.py,sha256=MNPlb0IsBjrlU5e438JlJ4DIKoBpBRAaYY3JhD3yHqk,601
5
+ demo_extractors/requirements.txt,sha256=E0tD6xBZldq6sQGTHng6k88lBeASOhmLJcdcjpcqBNE,6
6
+ demo_extractors/shared.py,sha256=2P1cyuRbHDvM9IRt3UZnwdyhxx7OWqNC83xLyV8Y190,305
7
+ demo_extractors/complex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ demo_extractors/complex/complex.py,sha256=tXrzj_zWIXbTOwj7Lezapk-qkrM-lfwcyjd5m-BYzdg,2322
9
+ demo_extractors/complex/complex_utils.py,sha256=aec8kJsYUrMPo-waihkVLt-0QpiOPkw7dDqfT9MNuHk,123
10
+ maco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ maco/base_test.py,sha256=cjGLEy2c69wl9sjn74QFz7X-VxWOfdin4W8MvYsXc4Q,2718
12
+ maco/cli.py,sha256=NTzV8eu9V0qQNttRo592j-Rdzac7q1NAMraqJF2h_6k,8171
13
+ maco/collector.py,sha256=LraWYlCA72FCmQP0dHWc-ekd7R1SxR6h6rMD95_6mMs,7077
14
+ maco/extractor.py,sha256=uGSGiCQ4jd8jFmfw2T99BGcY5iQJzXHcG_RoTIxClTE,2802
15
+ maco/utils.py,sha256=RbG36i04iWoe5gBUxbnbJ_lDvYY5OkYtiy0EdXF9OHw,20870
16
+ maco/yara.py,sha256=8RVaGyeUWY5f8_wfQ25lDX1bcXsb_VoSja85ZC2SqGw,2913
17
+ maco/model/__init__.py,sha256=ULdyHx8R5D2ICHZo3VoCk1YTlewTok36TYIpwx__pNY,45
18
+ maco/model/model.py,sha256=4uY88WphbP3iu-L2WjuYwtgZCS_wNul_hr0bAVuTpvc,23740
19
+ model_setup/maco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ model_setup/maco/base_test.py,sha256=cjGLEy2c69wl9sjn74QFz7X-VxWOfdin4W8MvYsXc4Q,2718
21
+ model_setup/maco/cli.py,sha256=NTzV8eu9V0qQNttRo592j-Rdzac7q1NAMraqJF2h_6k,8171
22
+ model_setup/maco/collector.py,sha256=LraWYlCA72FCmQP0dHWc-ekd7R1SxR6h6rMD95_6mMs,7077
23
+ model_setup/maco/extractor.py,sha256=uGSGiCQ4jd8jFmfw2T99BGcY5iQJzXHcG_RoTIxClTE,2802
24
+ model_setup/maco/utils.py,sha256=RbG36i04iWoe5gBUxbnbJ_lDvYY5OkYtiy0EdXF9OHw,20870
25
+ model_setup/maco/yara.py,sha256=8RVaGyeUWY5f8_wfQ25lDX1bcXsb_VoSja85ZC2SqGw,2913
26
+ model_setup/maco/model/__init__.py,sha256=ULdyHx8R5D2ICHZo3VoCk1YTlewTok36TYIpwx__pNY,45
27
+ model_setup/maco/model/model.py,sha256=4uY88WphbP3iu-L2WjuYwtgZCS_wNul_hr0bAVuTpvc,23740
28
+ pipelines/publish.yaml,sha256=xt3WNU-5kIICJgKIiiE94M3dWjS3uEiun-n4OmIssK8,1471
29
+ pipelines/test.yaml,sha256=btJVI-R39UBeYosGu7TOpU6V9ogFW3FT3ROtWygQGQ0,1472
30
+ tests/data/example.txt.cart,sha256=j4ZdDnFNVq7lb-Qi4pY4evOXKQPKG-GSg-n-uEqPhV0,289
31
+ tests/data/trigger_complex.txt,sha256=uqnLSrnyDGCmXwuPmZ2s8vdhH0hJs8DxvyaW_tuYY24,64
32
+ tests/data/trigger_complex.txt.cart,sha256=Z7qF1Zi640O45Znkl9ooP2RhSLAEqY0NRf51d-q7utU,345
33
+ tests/extractors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ tests/extractors/basic.py,sha256=r5eLCL6Ynr14nCBgtbLvUbm0NdrXizyc9c-4xBCNShU,828
35
+ tests/extractors/basic_longer.py,sha256=1ClU2QD-Y0TOl_loNFvEqIEpTR5TSVJ6zg9ZmC-ESJo,860
36
+ tests/extractors/test_basic.py,sha256=FLKekfSGM69HaiF7Vu_7D7KDXHZko-9hZkMO8_DoyYA,697
37
+ tests/extractors/bob/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ tests/extractors/bob/bob.py,sha256=G5aOoz58J0ZQK2_lA7HRxAzeLzBxssWxBTZcv1pSbi8,176
39
+ maco-1.2.7.dist-info/LICENSE.md,sha256=gMSjshPhXvV_F1qxmeNkKdBqGWkd__fEJf4glS504bM,1478
40
+ maco-1.2.7.dist-info/METADATA,sha256=09_OhgEFJ1kNPB6tg0NiJQmIrlLDB51bbR2rnrdW-wU,15855
41
+ maco-1.2.7.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
42
+ maco-1.2.7.dist-info/entry_points.txt,sha256=TpcwG1gedIg8Y7a9ZOv8aQpuwEUftCefDrAjzeP-o6U,39
43
+ maco-1.2.7.dist-info/top_level.txt,sha256=iMRwuzmrHA3zSwiSeMIl6FWhzRpn_st-I4fAv-kw5_o,49
44
+ maco-1.2.7.dist-info/RECORD,,
@@ -32,7 +32,7 @@ class BaseTest(unittest.TestCase):
32
32
  # I recommend something like os.path.join(__file__, "../../extractors")
33
33
  # if your extractors are in a folder 'extractors' next to a folder of tests
34
34
  path: str = None
35
- create_venv: bool=False
35
+ create_venv: bool = False
36
36
 
37
37
  @classmethod
38
38
  def setUpClass(cls) -> None:
model_setup/maco/cli.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """CLI example of how extractors can be executed."""
2
+
2
3
  import argparse
3
4
  import base64
4
5
  import binascii
@@ -150,6 +151,7 @@ def process_filesystem(
150
151
  logger.info(f"{num_analysed} analysed, {num_hits} hits, {num_extracted} extracted")
151
152
  return num_analysed, num_hits, num_extracted
152
153
 
154
+
153
155
  def main():
154
156
  parser = argparse.ArgumentParser(description="Run extractors over samples.")
155
157
  parser.add_argument("extractors", type=str, help="path to extractors")
@@ -165,7 +167,8 @@ def main():
165
167
  parser.add_argument(
166
168
  "--base64",
167
169
  action="store_true",
168
- help="Include base64 encoded binary data in output (can be large, consider printing to file rather than console)",
170
+ help="Include base64 encoded binary data in output "
171
+ "(can be large, consider printing to file rather than console)",
169
172
  )
170
173
  parser.add_argument("--logfile", type=str, help="file to log output")
171
174
  parser.add_argument("--include", type=str, help="comma separated extractors to run")
@@ -179,7 +182,9 @@ def main():
179
182
  parser.add_argument(
180
183
  "--create_venv",
181
184
  action="store_true",
182
- help="Creates venvs for every requirements.txt found (only applies when extractor path is a directory). This runs much slower than the alternative but may be necessary when there are many extractors with conflicting dependencies.",
185
+ help="Creates venvs for every requirements.txt found (only applies when extractor path is a directory). "
186
+ "This runs much slower than the alternative but may be necessary "
187
+ "when there are many extractors with conflicting dependencies.",
183
188
  )
184
189
  args = parser.parse_args()
185
190
  inc = args.include.split(",") if args.include else []
@@ -225,7 +230,7 @@ def main():
225
230
  pretty=args.pretty,
226
231
  force=args.force,
227
232
  include_base64=args.base64,
228
- create_venv=args.create_venv
233
+ create_venv=args.create_venv,
229
234
  )
230
235
 
231
236
 
@@ -4,6 +4,7 @@ import inspect
4
4
  import logging
5
5
  import logging.handlers
6
6
  import os
7
+ import sys
7
8
  from multiprocessing import Manager, Process, Queue
8
9
  from tempfile import NamedTemporaryFile
9
10
  from types import ModuleType
@@ -48,6 +49,15 @@ class Collector:
48
49
  create_venv: bool = False,
49
50
  ):
50
51
  """Discover and load extractors from file system."""
52
+ # maco requires the extractor to be imported directly, so ensure they are available on the path
53
+ full_path_extractors = os.path.abspath(path_extractors)
54
+ full_path_above_extractors = os.path.dirname(full_path_extractors)
55
+ # Modify the PATH so we can recognize this new package on import
56
+ if full_path_extractors not in sys.path:
57
+ sys.path.insert(1, full_path_extractors)
58
+ if full_path_above_extractors not in sys.path:
59
+ sys.path.insert(1, full_path_above_extractors)
60
+
51
61
  path_extractors = os.path.realpath(path_extractors)
52
62
  self.path: str = path_extractors
53
63
  self.extractors: Dict[str, Dict[str, str]] = {}
@@ -89,7 +99,7 @@ class Collector:
89
99
 
90
100
  # multiprocess logging is awkward - set up a queue to ensure we can log
91
101
  logging_queue = Queue()
92
- queue_handler = logging.handlers.QueueListener(logging_queue,*logging.getLogger().handlers)
102
+ queue_handler = logging.handlers.QueueListener(logging_queue, *logging.getLogger().handlers)
93
103
  queue_handler.start()
94
104
 
95
105
  # Find the extractors within the given directory
@@ -1 +1 @@
1
- from maco.model.model import *
1
+ from maco.model.model import * # noqa: F403
@@ -59,31 +59,48 @@ class CategoryEnum(str, Enum):
59
59
  # Malware related to an Advanced Persistent Threat (APT) group.
60
60
  apt = "apt"
61
61
 
62
- # A backdoor Trojan gives malicious users remote control over the infected computer. They enable the author to do anything they wish on the infected computer including sending, receiving, launching and deleting files, displaying data and rebooting the computer. Backdoor Trojans are often used to unite a group of victim computers to form a botnet or zombie network that can be used for criminal purposes.
62
+ # A backdoor Trojan gives malicious users remote control over the infected computer.
63
+ # They enable the author to do anything they wish on the infected computer including
64
+ # sending, receiving, launching and deleting files, displaying data and rebooting the computer.
65
+ # Backdoor Trojans are often used to unite a group of victim computers to form a botnet or
66
+ # zombie network that can be used for criminal purposes.
63
67
  backdoor = "backdoor"
64
68
 
65
- # Trojan Banker programs are designed to steal your account data for online banking systems, e-payment systems and credit or debit cards.
69
+ # Trojan Banker programs are designed to steal your account data for online banking systems,
70
+ # e-payment systems and credit or debit cards.
66
71
  banker = "banker"
67
72
 
68
- # A malware variant that modifies the boot sectors of a hard drive, including the Master Boot Record (MBR) and Volume Boot Record (VBR).
73
+ # A malware variant that modifies the boot sectors of a hard drive, including the Master Boot Record (MBR)
74
+ # and Volume Boot Record (VBR).
69
75
  bootkit = "bootkit"
70
76
 
71
- # A malicious bot is self-propagating malware designed to infect a host and connect back to a central server or servers that act as a command and control (C&C) center for an entire network of compromised devices, or botnet.
77
+ # A malicious bot is self-propagating malware designed to infect a host and connect back to a central server
78
+ # or servers that act as a command and control (C&C) center for an entire network of compromised devices,
79
+ # or botnet.
72
80
  bot = "bot"
73
81
 
74
- # A browser hijacker is defined as a form of unwanted software that modifies a web browser's settings without the user's permission. The result is the placement of unwanted advertising into the browser, and possibly the replacement of an existing home page or search page with the hijacker page.
82
+ # A browser hijacker is defined as a form of unwanted software that modifies a web browser's settings without
83
+ # the user's permission. The result is the placement of unwanted advertising into the browser,
84
+ # and possibly the replacement of an existing home page or search page with the hijacker page.
75
85
  browser_hijacker = "browser_hijacker"
76
86
 
77
- # Trojan bruteforcer are trying to brute force website in order to achieve something else (EX: Finding WordPress websites with default credentials).
87
+ # Trojan bruteforcer are trying to brute force website in order to achieve something else
88
+ # (EX: Finding WordPress websites with default credentials).
78
89
  bruteforcer = "bruteforcer"
79
90
 
80
- # A type of trojan that can use your PC to 'click' on websites or applications. They are usually used to make money for a malicious hacker by clicking on online advertisements and making it look like the website gets more traffic than it does. They can also be used to skew online polls, install programs on your PC, or make unwanted software appear more popular than it is.
91
+ # A type of trojan that can use your PC to 'click' on websites or applications.
92
+ # They are usually used to make money for a malicious hacker by clicking on online advertisements
93
+ # and making it look like the website gets more traffic than it does.
94
+ # They can also be used to skew online polls, install programs on your PC, or make unwanted software
95
+ # appear more popular than it is.
81
96
  clickfraud = "clickfraud"
82
97
 
83
98
  # Cryptocurrency mining malware.
84
99
  cryptominer = "cryptominer"
85
100
 
86
- # These programs conduct DoS (Denial of Service) attacks against a targeted web address. By sending multiple requests from your computer and several other infected computers, the attack can overwhelm the target address leading to a denial of service.
101
+ # These programs conduct DoS (Denial of Service) attacks against a targeted web address.
102
+ # By sending multiple requests from your computer and several other infected computers,
103
+ # the attack can overwhelm the target address leading to a denial of service.
87
104
  ddos = "ddos"
88
105
 
89
106
  # Trojan Downloaders can download and install new versions of malicious programs in the target system.
@@ -92,49 +109,66 @@ class CategoryEnum(str, Enum):
92
109
  # These programs are used by hackers in order to install malware or to prevent the detection of malicious programs.
93
110
  dropper = "dropper"
94
111
 
95
- # Exploit kits are programs that contain data or code that takes advantage of a vulnerability within an application that is running in the target system.
112
+ # Exploit kits are programs that contain data or code that takes advantage of a vulnerability
113
+ # within an application that is running in the target system.
96
114
  exploitkit = "exploitkit"
97
115
 
98
- # Trojan FakeAV programs simulate the activity of antivirus software. They are designed to extort money in return for the detection and removal of threat, even though the threats that they report are actually non-existent.
116
+ # Trojan FakeAV programs simulate the activity of antivirus software.
117
+ # They are designed to extort money in return for the detection and removal of threat, even though the
118
+ # threats that they report are actually non-existent.
99
119
  fakeav = "fakeav"
100
120
 
101
121
  # A type of tool that can be used to allow and maintain unauthorized access to your PC.
102
122
  hacktool = "hacktool"
103
123
 
104
- # A program that collects your personal information, such as your browsing history, and uses it without adequate consent.
124
+ # A program that collects your personal information, such as your browsing history,
125
+ # and uses it without adequate consent.
105
126
  infostealer = "infostealer"
106
127
 
107
- # A keylogger monitors and logs every keystroke it can identify. Once installed, the virus either keeps track of all the keys and stores the information locally, after which the hacker needs physical access to the computer to retrieve the information, or the logs are sent over the internet back to the hacker.
128
+ # A keylogger monitors and logs every keystroke it can identify.
129
+ # Once installed, the virus either keeps track of all the keys and stores the information locally,
130
+ # after which the hacker needs physical access to the computer to retrieve the information,
131
+ # or the logs are sent over the internet back to the hacker.
108
132
  keylogger = "keylogger"
109
133
 
110
134
  # A program that loads another application / memory space.
111
135
  loader = "loader"
112
136
 
113
- # A type of malware that hides its code and purpose to make it more difficult for security software to detect or remove it.
137
+ # A type of malware that hides its code and purpose to make it more difficult for
138
+ # security software to detect or remove it.
114
139
  obfuscator = "obfuscator"
115
140
 
116
- # Point-of-sale malware is usually a type of malware that is used by cybercriminals to target point of sale (POS) and payment terminals with the intent to obtain credit card and debit card information.
141
+ # Point-of-sale malware is usually a type of malware that is used by cybercriminals to target point of sale (POS)
142
+ # and payment terminals with the intent to obtain credit card and debit card information.
117
143
  pos = "pos"
118
144
 
119
- # This type of trojan allows unauthorized parties to use the infected computer as a proxy server to access the Internet anonymously.
145
+ # This type of trojan allows unauthorized parties to use the infected computer as a proxy server
146
+ # to access the Internet anonymously.
120
147
  proxy = "proxy"
121
148
 
122
149
  # A program that can be used by a remote hacker to gain access and control of an infected machine.
123
150
  rat = "rat"
124
151
 
125
- # This type of malware can modify data in the target computer so the operating system will stop running correctly or the data is no longer accessible. The criminal will only restore the computer state or data after a ransom is paid to them (mostly using cryptocurrency).
152
+ # This type of malware can modify data in the target computer so the operating system
153
+ # will stop running correctly or the data is no longer accessible.
154
+ # The criminal will only restore the computer state or data after a ransom is paid to them
155
+ # (mostly using cryptocurrency).
126
156
  ransomware = "ransomware"
127
157
 
128
158
  # A reverse proxy is a server that receives requests from the internet and forwards them to a small set of servers.
129
159
  reverse_proxy = "reverse_proxy"
130
160
 
131
- # Rootkits are designed to conceal certain objects or activities in the system. Often their main purpose is to prevent malicious programs being detected in order to extend the period in which programs can run on an infected computer.
161
+ # Rootkits are designed to conceal certain objects or activities in the system.
162
+ # Often their main purpose is to prevent malicious programs being detected
163
+ # in order to extend the period in which programs can run on an infected computer.
132
164
  rootkit = "rootkit"
133
165
 
134
- # This type of malware scan the internet / network(s) / system(s) / service(s) to collect information. That information could be used later to perpetuate an cyber attack.
166
+ # This type of malware scan the internet / network(s) / system(s) / service(s) to collect information.
167
+ # That information could be used later to perpetuate an cyber attack.
135
168
  scanner = "scanner"
136
169
 
137
- # Scareware is a form of malware which uses social engineering to cause shock, anxiety, or the perception of a threat in order to manipulate users into buying unwanted software.
170
+ # Scareware is a form of malware which uses social engineering to cause shock, anxiety,
171
+ # or the perception of a threat in order to manipulate users into buying unwanted software.
138
172
  scareware = "scareware"
139
173
 
140
174
  # Malware that is sending spam.
model_setup/maco/utils.py CHANGED
@@ -46,6 +46,7 @@ UV_BIN = find_uv_bin()
46
46
  PIP_CMD = f"{UV_BIN} pip"
47
47
  VENV_CREATE_CMD = f"{UV_BIN} venv"
48
48
 
49
+
49
50
  class Base64Decoder(json.JSONDecoder):
50
51
  def __init__(self, *args, **kwargs):
51
52
  json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs)
@@ -179,11 +180,9 @@ def scan_for_extractors(root_directory: str, scanner: yara.Rules, logger: Logger
179
180
  for pattern in [RELATIVE_FROM_IMPORT_RE, RELATIVE_FROM_RE]:
180
181
  for match in pattern.findall(data):
181
182
  depth = match.count(".")
182
- data = data.replace(
183
- f"from {match}",
184
- f"from {'.'.join(split[depth - 1 : split.index(package) + 1][::-1])}{'.' if pattern == RELATIVE_FROM_RE else ''}",
185
- 1,
186
- )
183
+ abspath = ".".join(split[depth - 1 : split.index(package) + 1][::-1])
184
+ abspath += "." if pattern == RELATIVE_FROM_RE else ""
185
+ data = data.replace(f"from {match}", f"from {abspath}", 1)
187
186
  f.write(data)
188
187
 
189
188
  if scanner.match(path):
@@ -222,7 +221,12 @@ def _install_required_packages(create_venv: bool, directories: List[str], python
222
221
  subprocess.run(cmd.split(" ") + [venv_path], capture_output=True, env=env)
223
222
 
224
223
  # Install/Update the packages in the environment
225
- install_command = PIP_CMD.split(" ") + ["install", "-U"]
224
+ install_command = PIP_CMD.split(" ") + ["install"]
225
+ # When running locally, only install packages to required spec.
226
+ # This prevents issues during maco development and building extractors against local libraries.
227
+ if create_venv:
228
+ # when running in custom virtual environment, always upgrade packages.
229
+ install_command.append("-U")
226
230
 
227
231
  # Update the pip install command depending on where the dependencies are coming from
228
232
  if "requirements.txt" in req_files:
@@ -307,8 +311,10 @@ def register_extractors(
307
311
  parent_directory = os.path.dirname(current_directory)
308
312
  if venvs and package_name in sys.modules:
309
313
  # this may happen as part of testing if some part of the extractor code was directly imported
310
- logger.warning(f"Looks like {package_name} is already loaded. "
311
- "If your maco extractor overlaps an existing package name this could cause problems.")
314
+ logger.warning(
315
+ f"Looks like {package_name} is already loaded. "
316
+ "If your maco extractor overlaps an existing package name this could cause problems."
317
+ )
312
318
 
313
319
  try:
314
320
  # Modify the PATH so we can recognize this new package on import
@@ -383,6 +389,7 @@ def register_extractors(
383
389
  # We were able to find all the extractor files
384
390
  break
385
391
 
392
+
386
393
  def proxy_logging(queue: multiprocessing.Queue, callback: Callable[[ModuleType, str], None], *args, **kwargs):
387
394
  """Ensures logging is set up correctly for a child process and then executes the callback."""
388
395
  logger = logging.getLogger()
@@ -391,6 +398,7 @@ def proxy_logging(queue: multiprocessing.Queue, callback: Callable[[ModuleType,
391
398
  logger.addHandler(qh)
392
399
  callback(*args, **kwargs, logger=logger)
393
400
 
401
+
394
402
  def import_extractors(
395
403
  extractor_module_callback: Callable[[ModuleType, str], bool],
396
404
  *,
@@ -399,14 +407,24 @@ def import_extractors(
399
407
  create_venv: bool,
400
408
  logger: Logger,
401
409
  python_version: str = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
410
+ skip_install: bool = False,
402
411
  ):
403
412
  extractor_dirs, extractor_files = scan_for_extractors(root_directory, scanner, logger)
404
413
 
405
414
  logger.info(f"Extractor files found based on scanner ({len(extractor_files)}).")
406
415
  logger.debug(extractor_files)
407
416
 
408
- # Install packages into the current environment or dynamically created virtual environments
409
- venvs = _install_required_packages(create_venv, extractor_dirs, python_version, logger)
417
+ if not skip_install:
418
+ # Install packages into the current environment or dynamically created virtual environments
419
+ venvs = _install_required_packages(create_venv, extractor_dirs, python_version, logger)
420
+ else:
421
+ # Look for pre-existing virtual environments, if any
422
+ logger.info("Checking for pre-existing virtual environment(s)..")
423
+ venvs = [
424
+ os.path.join(root, VENV_DIRECTORY_NAME)
425
+ for root, dirs, _ in os.walk(root_directory)
426
+ if VENV_DIRECTORY_NAME in dirs
427
+ ]
410
428
 
411
429
  # With the environment prepared, we can now hunt for the extractors and register them
412
430
  logger.info("Registering extractors..")
@@ -416,6 +434,7 @@ def import_extractors(
416
434
  # holds cached extractors when not running in venv mode
417
435
  _loaded_extractors: Dict[str, Extractor] = {}
418
436
 
437
+
419
438
  def run_extractor(
420
439
  sample_path,
421
440
  module_name,
@@ -438,7 +457,7 @@ def run_extractor(
438
457
  extractor = _loaded_extractors[key]
439
458
  if extractor.yara_compiled:
440
459
  matches = extractor.yara_compiled.match(sample_path)
441
- loaded = extractor.run(open(sample_path, 'rb'), matches=matches)
460
+ loaded = extractor.run(open(sample_path, "rb"), matches=matches)
442
461
  else:
443
462
  # execute extractor in child process with separate virtual environment
444
463
  # Write temporary script in the same directory as extractor to resolve relative imports
@@ -477,7 +496,7 @@ def run_extractor(
477
496
  try:
478
497
  # Load results and return them
479
498
  output.seek(0)
480
- loaded = json.load(output, cls=json_decoder)
499
+ loaded = json.load(output, cls=json_decoder)
481
500
  except Exception as e:
482
501
  # If there was an error raised during runtime, then propagate
483
502
  delim = f'File "{module_path}"'
model_setup/maco/yara.py CHANGED
@@ -3,7 +3,6 @@ from collections import namedtuple
3
3
  from itertools import cycle
4
4
  from typing import Dict
5
5
 
6
- import yara
7
6
  import yara_x
8
7
 
9
8
  RULE_ID_RE = re.compile("(\w+)? ?rule (\w+)")
pipelines/test.yaml CHANGED
@@ -7,6 +7,27 @@ pool:
7
7
  vmImage: "ubuntu-22.04"
8
8
 
9
9
  jobs:
10
+ - job: style_test
11
+ strategy:
12
+ matrix:
13
+ Python3_12:
14
+ python.version: "3.12"
15
+ timeoutInMinutes: 10
16
+
17
+ steps:
18
+ - task: UsePythonVersion@0
19
+ displayName: Set python version
20
+ inputs:
21
+ versionSpec: "$(python.version)"
22
+
23
+ - script: |
24
+ python -m pip install -U tox
25
+ displayName: Install tox
26
+
27
+ - script: |
28
+ python -m tox -e style
29
+ displayName: "Run style tests"
30
+
10
31
  - job: run_test
11
32
  strategy:
12
33
  matrix:
@@ -1,7 +1,4 @@
1
- from io import BytesIO
2
- from typing import List, Optional
3
-
4
- from maco import extractor, model, yara
1
+ from maco import extractor
5
2
 
6
3
 
7
4
  class Bob(extractor.Extractor):
@@ -1,44 +0,0 @@
1
- demo_extractors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- demo_extractors/elfy.py,sha256=AAFr5i1aivPwO4nycyXJEud57EpVNA-5k_2GicWesbY,771
3
- demo_extractors/limit_other.py,sha256=8Z7X0cXUyZuK3MhDtObMWmdruRj5hgFdDi_VVGXqRx4,1123
4
- demo_extractors/nothing.py,sha256=3aeQJTY-dakmVXmyfmrRM8YCQVT7q3bq880DFH1Ol_Y,607
5
- demo_extractors/requirements.txt,sha256=E0tD6xBZldq6sQGTHng6k88lBeASOhmLJcdcjpcqBNE,6
6
- demo_extractors/shared.py,sha256=2P1cyuRbHDvM9IRt3UZnwdyhxx7OWqNC83xLyV8Y190,305
7
- demo_extractors/complex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- demo_extractors/complex/complex.py,sha256=tXrzj_zWIXbTOwj7Lezapk-qkrM-lfwcyjd5m-BYzdg,2322
9
- demo_extractors/complex/complex_utils.py,sha256=aec8kJsYUrMPo-waihkVLt-0QpiOPkw7dDqfT9MNuHk,123
10
- maco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- maco/base_test.py,sha256=EPxCun9Tv91V-lFpaenn14tPyW17TPvXVH4AjE3t6js,2716
12
- maco/cli.py,sha256=fIeUXOgOxcecmAkl6OAdnjBKqk1gBPv1ryWe50pT60g,8135
13
- maco/collector.py,sha256=Vlo7KcJC7TKZFTElv8i_f_hvWEnlWCRzOP1xOc9x7vk,6532
14
- maco/extractor.py,sha256=uGSGiCQ4jd8jFmfw2T99BGcY5iQJzXHcG_RoTIxClTE,2802
15
- maco/utils.py,sha256=K41c-H7naaoiEYf0WNfP054IxwvHPujsbmmzgTizuLU,20159
16
- maco/yara.py,sha256=vPzCqauVp52ivcTdt8zwrYqDdkLutGlesma9DhKPzHw,2925
17
- maco/model/__init__.py,sha256=SJrwdn12wklUFm2KoIgWjX_KgvJxCM7Ca9ntXOneuzc,31
18
- maco/model/model.py,sha256=ngen4ViyLdRo_z_TqZBjw2DN0NrRLpuxOy15-6QmtNw,23536
19
- model_setup/maco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- model_setup/maco/base_test.py,sha256=EPxCun9Tv91V-lFpaenn14tPyW17TPvXVH4AjE3t6js,2716
21
- model_setup/maco/cli.py,sha256=fIeUXOgOxcecmAkl6OAdnjBKqk1gBPv1ryWe50pT60g,8135
22
- model_setup/maco/collector.py,sha256=Vlo7KcJC7TKZFTElv8i_f_hvWEnlWCRzOP1xOc9x7vk,6532
23
- model_setup/maco/extractor.py,sha256=uGSGiCQ4jd8jFmfw2T99BGcY5iQJzXHcG_RoTIxClTE,2802
24
- model_setup/maco/utils.py,sha256=K41c-H7naaoiEYf0WNfP054IxwvHPujsbmmzgTizuLU,20159
25
- model_setup/maco/yara.py,sha256=vPzCqauVp52ivcTdt8zwrYqDdkLutGlesma9DhKPzHw,2925
26
- model_setup/maco/model/__init__.py,sha256=SJrwdn12wklUFm2KoIgWjX_KgvJxCM7Ca9ntXOneuzc,31
27
- model_setup/maco/model/model.py,sha256=ngen4ViyLdRo_z_TqZBjw2DN0NrRLpuxOy15-6QmtNw,23536
28
- pipelines/publish.yaml,sha256=xt3WNU-5kIICJgKIiiE94M3dWjS3uEiun-n4OmIssK8,1471
29
- pipelines/test.yaml,sha256=3KOoo-8SqP_bTAscsz5V3xxnuL91J-62mTjnQD1Btag,1019
30
- tests/data/example.txt.cart,sha256=j4ZdDnFNVq7lb-Qi4pY4evOXKQPKG-GSg-n-uEqPhV0,289
31
- tests/data/trigger_complex.txt,sha256=uqnLSrnyDGCmXwuPmZ2s8vdhH0hJs8DxvyaW_tuYY24,64
32
- tests/data/trigger_complex.txt.cart,sha256=Z7qF1Zi640O45Znkl9ooP2RhSLAEqY0NRf51d-q7utU,345
33
- tests/extractors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- tests/extractors/basic.py,sha256=r5eLCL6Ynr14nCBgtbLvUbm0NdrXizyc9c-4xBCNShU,828
35
- tests/extractors/basic_longer.py,sha256=1ClU2QD-Y0TOl_loNFvEqIEpTR5TSVJ6zg9ZmC-ESJo,860
36
- tests/extractors/test_basic.py,sha256=FLKekfSGM69HaiF7Vu_7D7KDXHZko-9hZkMO8_DoyYA,697
37
- tests/extractors/bob/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- tests/extractors/bob/bob.py,sha256=Gy5p8KssJX87cwa9vVv8UBODF_ulbUteZXh15frW2hs,247
39
- maco-1.2.5.dist-info/LICENSE.md,sha256=gMSjshPhXvV_F1qxmeNkKdBqGWkd__fEJf4glS504bM,1478
40
- maco-1.2.5.dist-info/METADATA,sha256=cJ7x_shBhDgKVjkq_e2d94aj3qiUzi0lt7f3lPO334U,15610
41
- maco-1.2.5.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
42
- maco-1.2.5.dist-info/entry_points.txt,sha256=TpcwG1gedIg8Y7a9ZOv8aQpuwEUftCefDrAjzeP-o6U,39
43
- maco-1.2.5.dist-info/top_level.txt,sha256=iMRwuzmrHA3zSwiSeMIl6FWhzRpn_st-I4fAv-kw5_o,49
44
- maco-1.2.5.dist-info/RECORD,,
File without changes