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