phoreal/phoreal.py (51 lines of code) (raw):

import logging from malduck.extractor import Extractor from malduck.procmem import ProcessMemory from malduck.yara import YaraRuleMatch from ..utils import Config, get_rule_metadata logger = logging.getLogger(__name__) class Phoreal(Extractor): family = "phoreal" yara_rules = ("phoreal",) overrides = [] @Extractor.rule def phoreal(self, p: ProcessMemory, match: YaraRuleMatch) -> Config | bool: _info: Config = get_rule_metadata(match) return _info @Extractor.extractor("rcdata") def PHOREAL_RC4_key(self, p: ProcessMemory, addr: int): from malduck import rc4 key_size = 17 # apparently hardcoded in phoreal key_addr = addr + 6 # offset from start of string ct_addr = key_addr + 17 max_size = 200 key = bytearray() ct = bytearray() logger.info("[+] Found RC4 passphrase @ %X" % key_addr) for offset in range(0, key_size): o = p.uint8v(key_addr + offset) if o: key.append(o) logger.info("[+] RC4 passphrase: " + key.hex()) nc = 0 # null counter for offset in range(0, max_size): o = p.uint8v(ct_addr + offset) if o: ct.append(o) if o == 0: nc += 1 else: nc = 0 if nc == 2: break logger.info("[+] RC4 cyphertext: " + ct.hex()) rc4_decode = rc4(key, ct) logger.info("[+] RC4 decrypted plaintext: %s" % str(rc4_decode)) domains = str(rc4_decode).split(";") domains[0] = domains[0].split("'")[1] del domains[-1] conf = { "rc4_key": key.hex(), self.family: {"plaintext": str(rc4_decode), "domains": domains}, } return conf