azorult/azorult.py (32 lines of code) (raw):

import itertools import logging import re import string from malduck.extractor import Extractor from malduck.procmem import ProcessMemory from malduck.yara import YaraRuleMatch from ..utils import Config, get_rule_metadata log = logging.getLogger(__name__) __author__ = "c3rb3ru5" __version__ = "1.0.0" CONTROL_CHARS = "".join(map(chr, itertools.chain(range(0x00, 0x20), range(0x7F, 0xA0)))) CONTROL_CHAR_RE = re.compile(f"{re.escape(CONTROL_CHARS)}") def remove_control_chars(s: str) -> str: return CONTROL_CHAR_RE.sub("", s) class Azorult(Extractor): """ Azorult C2 Domain Configuration Extractor """ family = "azorult" yara_rules = ("azorult",) @Extractor.rule def azorult(self, p: ProcessMemory, match: YaraRuleMatch) -> Config | bool: _info: Config = get_rule_metadata(match) return _info @Extractor.extractor("ref_c2") def ref_c2(self, p: ProcessMemory, addr: int) -> dict | None: c2_list_va = p.uint32v(addr + 21) c2: str = "" if c2_list_va: c2 = remove_control_chars(p.asciiz(c2_list_va).decode("utf-8")) if len(c2) <= 0: return None config = {"family": self.family, "urls": [c2]} return config