Sign in

Indicators

A capability tagger that answers a different question from the CWE catalog: not what is wrong with this binary? but what does this binary do?

Nine behavior categories · ~160 curated rules · 430 macOS-relevant MITRE ATT&CK techniques mapped · 28 malware-family fingerprints · 6 evidence types · facts-only output.

Each hit carries a stable rule id, a category, an evidence type, optional matched_text and matched_va, and zero or more MITRE ATT&CK technique IDs. No severity, no score, no risk rating — a keylogger and a productivity app that listens for global hotkeys produce the same keystroke.global_hook indicator. Scoring those facts into a verdict lives in Malware or in the consumer's own policy layer.

The taxonomy mirrors Mandiant's capa project, trimmed to nine categories that make sense for a static analyzer running over macOS, Linux, and Windows binaries.

The nine behavior categories

CategoryWhat it tagsRules
PersistenceHow the binary maintains presence across reboots36
CollectionHow it gathers data from the user or system13
CommunicationHow it talks to remote endpoints (C2 shapes)29
Host interactionShell, post-compromise utilities, reverse shells, software-stack ID36
Data manipulationCryptographic primitives embedded inline17
Malware familyString-level family fingerprints (not attribution)28
TargetingImpersonation and brand-spoofing1
Anti-analysisPacking, obfuscation, anti-debugreserved v1
Load codeDynamic loading abusereserved v1

The two reserved categories carry no rules in v1 — the populated signals for those areas live in the Findings CWE detectors (CWE-693 anti-debug, CWE-94 dynamic load) and the consistency layer. The empty category is held open so consumers can rely on the nine-element taxonomy regardless.

Persistence

LaunchAgent and LaunchDaemon plist paths (~/Library/LaunchAgents/, /Library/LaunchDaemons/, /System/Library/LaunchDaemons/), LoginItem (SMLoginItemSetEnabled), shell-profile injection (.zshrc, .bashrc, .bash_profile, .zprofile, .zshenv), legacy Unix (crontab, emond, /etc/rc.common), Linux systemd and cron equivalents, and the two dynamic-linker injection variables (DYLD_INSERT_LIBRARIES, LD_PRELOAD). Substring-only by design — false positives on documentation that mentions these paths are accepted because the alternative (interprocedural taint to a write site) misses the legitimate persistence shapes.

Collection

Clipboard harvest (NSPasteboard with dataForType), keychain dump (SecItemCopyMatching with kSecMatchLimitAll), credential access via UI primitives (synthetic keystrokes to a password field), file-tree walking with find plus a cp or tar outbound. Composite rules require multiple primitives co-located in the same function.

Communication

Raw IPv4-and-port literals (%d.%d.%d.%d:%d), Tor onion v2 and v3 domains, dynamic-DNS providers (duckdns.org, no-ip.com, dyndns.org), DNS TXT tunneling shapes (dnscat, dns2tcp), protocol-specific webhook templates (Slack, Discord, Mattermost), Mirai and Mozi IoT-botnet markers, Stratum mining-pool URI templates (stratum+tcp://), and the IRC PRIVMSG shape older bot families still emit.

Host interaction

Shell markers (/bin/sh -c, /bin/bash -c, osascript -e), post-compromise utilities (base64 -d, chmod +x, xattr -d com.apple.quarantine, SetFile -a V), reverse-shell patterns (nc -e, bash -i >& /dev/tcp/), privilege escalation (chmod 4755, chown root:wheel), and Linux/IoT patterns that show up in BusyBox-bundled implants.

Data manipulation

Cryptographic constants scanned as byte patterns against non-__TEXT sections: AES forward and reverse S-boxes, the AES Rcon table, MD5 / SHA-1 / SHA-256 / SHA-512 init constants, ChaCha20 and Salsa20 "expand 32-byte k" / "expand 16-byte k" sigmas, the Curve25519 base point, secp256k1 generator coordinates, the eight DES S-boxes, and the Blowfish P-array. A match means the constant is present in the binary's data — strong evidence the algorithm is implemented inline rather than called through libcrypto, useful when a binary appears to avoid the system crypto framework.

Targeting

Impersonation and brand-spoofing. One rule today: a com.apple.* bundle identifier signed by a team ID that isn't Apple's. More rules will land here as the curation set grows.

Anti-analysis

Reserved category in v1, empty rule table. Anti-debug and obfuscation signals come from Findings CWE-693 and the consistency layer's AdhocPrivileged and PrivateEntitlementNonApple checks.

Load code

Reserved category in v1, empty rule table. Dynamic-loading abuse comes from Findings CWE-94, which produces per-call-site findings rather than coarse capability hits.

Malware family

Family-attributable string patterns. See Family fingerprints below for the 28 seeded rules and the critical caveat about what a hit actually claims.

Evidence types

Every hit names where the evidence came from. The shape determines how matched_text and matched_va are populated.

EvidenceSourceAnchored VA?
Raw stringC-string pool match in __TEXT,__cstringyes — string VA
CFStringDecoded CFString body matchyes — struct VA
SelectorObjective-C selector namesometimes (selectors don't always carry a VA)
ImportImport-symbol match (SecItemCopyMatching, CGEventTapCreate)yes — IAT address
EntitlementKey or value from the code-signature plistno — metadata, not code
Section bytesByte-pattern match in a named section (the crypto-constant scans)yes — match offset relative to section base

For cross-surface predicates that don't anchor to a specific instruction — the targeting bundle-ID-vs-team-ID check, for example — matched_text carries the implicated string and the VA field is absent.

MITRE ATT&CK mapping

Every rule declares zero or more canonical ATT&CK technique IDs. The current snapshot covers 430 macOS-relevant techniques derived from MITRE's enterprise-attack.json and frozen in the build; reproducibility wins over freshness.

T-numbers use the canonical sub-technique form. Sample mappings:

RuleATT&CK
persistence.launch_agentT1543.001 — Create or Modify System Process: Launch Agent
shell.curl_pipe_shT1105 + T1059.004 — Ingress Tool Transfer + Unix Shell
crypto.aes_sbox_forwardT1027 + T1573.001 — Obfuscated Files or Information + Encrypted Channel
targeting.bundle_id_apple_domainT1036.005 — Masquerading: Match Legitimate Name or Location
keychain.security_find_internet_passwordT1555.001 — Credentials from Password Stores: Keychain

Rules can tag multiple T-numbers; the per-binary DNA vector materializes the union of all matched techniques, deduplicated and sorted. A consumer that wants per-tactic counts (the columns of the ATT&CK matrix — persistence, command-and-control, credential-access, defense-evasion, and so on) looks each T-number up in the frozen technique table and buckets by tactic.

Family fingerprints

The malware-family category houses 28 rules split into two groups.

Objective-See 2025 concretes — 8 multi-predicate rules across five families. Curated from Patrick Wardle's Objective-See 2025 macOS malware roundup. Each rule requires its predicate set to co-occur so a single shared string can't fire it:

Legacy stubs — 20 single-predicate rules. Single-needle placeholders from earlier threat-research material, expanded as triage data accumulates: CloudMensis, XCSSET, CrescentCore, Shlayer, Silver Sparrow, Pirrit, OSAMiner, Dacls, IPStorm, KeRanger, EvilQuest, WindTail, FruitFly, MacRansom, OceanLotus, Komplex, Snake, XAgent, Lazarus, WireLurker. Weaker signals than the multi-predicate concretes — they'll gain co-occurring predicates as the per-family corpus grows.

The critical caveat. A family hit means this binary shares strings with samples attributed to family X. It does not mean this binary is family X. The evidence is string-level; attribution requires more. Downstream consumers own any thresholding.

What this surface does not do

Where this fits

Indicators are one of four security surfaces. They feed the Malware classifier directly — the indicator-category aggregation rules (+10 per Communication hit, +10 per Collection hit, +15 per Anti-analysis hit, +25 per Malware-family hit) are how the malware composer turns capability facts into a tier verdict. They are independently consumed by openbinary's per-binary capability view, the per-package compare view, and external pipelines that want a stable feature stream without a verdict attached.

See Findings for the CWE catalog, Malware for the verdict surface, and CVEs & SBOM for the parallel version-based surface that runs on the same input.