mcpField
Y
yara-rule-authoring

yara-rule-authoring

github.com/trailofbits安全7.9k5.1k 次安装今天更新
代码仓库

关于 yara-rule-authoring

用于编写和审查 YARA-X 恶意软件检测规则的技能,面向安全分析人员,涵盖特征选择、性能检查、误报排查及旧版 YARA 迁移。

主要功能

  1. 01编写 YARA-X 规则
  2. 02分析字符串与 atom
  3. 03条件和性能指导
  4. 04排查误报
  5. 05迁移旧版 YARA 规则

适用场景

  1. 01编写恶意软件家族检测规则
  2. 02检查规则误报
  3. 03优化运行缓慢的规则集
  4. 04将规则迁移到 YARA-X

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trailofbits/skills --skill yara-rule-authoring

安装后在 Claude Code 中输入/yara-rule-authoring确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
assets/
trail-of-bits-mark.svg
examples/
MAL_Mac_ProtonRAT_Jan25.yar
MAL_NPM_SupplyChain_Jan25.yar
MAL_Win_Remcos_Jan25.yar
SUSP_CRX_SuspiciousPermissions.yar
SUSP_JS_Obfuscation_Jan25.yar
references/
crx-module.md
dex-module.md
performance.md
strings.md
style-guide.md
testing.md
scripts/
atom_analyzer.py
pyproject.toml
review.sh
test_yara_rules.py
uv.lock
yara_lint.py
yara_rules.py
workflows/
rule-development.md

详细介绍

YARA-X 规则编写

编写能够检测恶意软件且不会造成大量误报的规则。

请从已安装的此 SKILL.md 所在目录解析 linter、atom analyzer 和 review helper。 在下方命令中,将每个 <resolved-...-path> 替换为对应脚本的绝对路径,并保留引号。除非传入绝对输入路径,否则规则文件或目录仍相对于当前工作目录。

此技能面向 YARA-X,它是基于 Rust 的旧版 YARA 后继版本——正则表达式速度快 5–10 倍,错误提示更完善,内置格式化程序,验证更严格,包含新模块(crx、dex),且 99% 的规则兼容。它为 VirusTotal 的生产系统提供支持。使用 brew install yara-x 或 cargo install yara-x 安装;其 CLI 为 yr。现有规则请参阅从旧版 YARA 迁移。

核心原则

  1. 字符串必须生成优质原子——YARA 会提取 4 字节子序列以实现快速匹配。包含重复字节、常见序列或长度不足 4 字节的字符串,会导致字节码在过多文件上进行缓慢验证。

  2. 针对特定家族,而非类别——“检测勒索软件”会变成什么都检测不到,或者什么都检测到。“检测 LockBit 3.0 配置提取例程”才能精准命中目标。

  3. 部署前先使用良性文件进行测试——如果规则会在 Windows 系统文件上触发,那就毫无用处。请使用 VirusTotal 的良性文件库或自己的干净文件集进行验证。

  4. 先用开销低的检查快速筛选——filesize(即时),然后是魔数(几乎即时),再然后是字符串(开销低),最后是模块(开销高)。

  5. 元数据就是文档——未来的你(以及团队)需要知道规则会检测什么、原因是什么,以及样本来源。

适用场景

  • 编写用于恶意软件检测的新 YARA-X 规则
  • 审查现有规则的质量或性能问题
  • 优化运行缓慢的规则集
  • 将 IOC 或威胁情报转换为检测特征
  • 调试误报问题
  • 准备用于生产部署的规则
  • 将旧版 YARA 规则迁移到 YARA-X
  • 分析 Chrome 扩展(crx 模块)或 Android 应用(dex 模块)

不适用场景

  • 需要反汇编的静态分析 → 使用 Ghidra/IDA 技能
  • 动态恶意软件分析 → 使用沙箱分析技能
  • 基于网络的检测 → 使用 Suricata/Snort 技能
  • 使用 Volatility 进行内存取证 → 使用内存取证技能
  • 简单的基于哈希的检测 → 直接使用哈希列表

平台注意事项

YARA 可处理任何文件类型。请根据目标调整模式:

平台魔数不良字符串良好字符串
Windows PEuint16(0) == 0x5A4DAPI 名称、Windows 路径Mutex 名称、PDB 路径
macOS Mach-Ouint32(0) == 0xFEEDFACE(32 位)、0xFEEDFACF(64 位)、uint32be(0) == 0xCAFEBABE(通用二进制)常见的 Obj-C 方法键盘记录器字符串、持久化路径
JavaScript/Node(不需要)require、fetch、axios混淆器特征、eval+decode 链
npm/pip 包(不需要)postinstall、dependencies可疑包名、数据外传 URL
Office 文档uint32(0) == 0x04034B50VBA 关键字宏自动执行、编码后的载荷
VS Code 扩展(不需要)vscode.workspace不常见的 activationEvents、隐藏文件访问
Chrome 扩展使用 crx 模块常见 Chrome API滥用权限、清单异常
Android 应用使用 dex 模块标准 DEX 结构混淆类、可疑权限

**uintNN() 按小端序读取。**请将常量按字节顺序反转后填写,或者使用 uintNNbe() 并按文件中的顺序填写。ZIP/OOXML 文件以字节 50 4B 03 04 开头,因此应写为 uint32(0) == 0x04034B50——uint32(0) == 0x504B0304 可以正常编译,却永远不会匹配任何内容。同样的问题也会出现在 Mach-O 通用二进制中:磁盘上的字节为 CA FE BA BE,因此 uint32(0) == 0xCAFEBABE 是无效分支;请写成 uint32be(0) == 0xCAFEBABE 或 uint32(0) == 0xBEBAFECA。在信任任何魔数检查之前,请使用一个已知良好的样本通过 yr scan 验证。

macOS 恶意软件检测

目前还没有专用的 Mach-O 模块——请使用魔数和字符串模式。良好的指标包括:

  • 键盘记录器痕迹:CGEventTapCreate、kCGEventKeyDown
  • SSH 隧道字符串:ssh -D、tunnel、socks
  • 持久化路径:~/Library/LaunchAgents、/Library/LaunchDaemons
  • 凭据窃取:security find-generic-password、keychain
// Pattern from Airbnb BinaryAlert
rule SUSP_Mac_ProtonRAT
{
    strings:
        $lib1 = "SRWebSocket" ascii          // Library indicators
        $lib2 = "SocketRocket" ascii
        $behav1 = "SSH tunnel not launched" ascii   // Behavioral indicators
        $behav2 = "Keylogger" ascii
    condition:
        (uint32(0) == 0xFEEDFACF or uint32be(0) == 0xCAFEBABE) and
        any of ($lib*) and any of ($behav*)
}
JavaScript 检测
目标方法
npm 包package.json 模式、postinstall/preinstall 钩子、数据外传组合:fetch + 环境变量访问 + 凭据路径
Chrome 扩展crx 模块
其他扩展清单模式、后台脚本行为
独立 JS混淆标记(eval+atob、fromCharCode 链)、独特的函数/变量名、打包载荷
压缩/webpack 包打包后仍保留的独特字符串(URL、魔数);避免使用函数名——它们会被混淆

**良好的 JS 字符串:**Ethereum 函数选择器——{ a9 05 9c bb }(transfer(address,uint256))、{ 70 a0 82 31 }(balanceOf(address));用于隐写术的零宽字符——{ E2 80 8B E2 80 8C };混淆器特征——_0x、var _0x;特定的 C2 域名和 webhook URL。

不良的 JS 字符串:require、fetch、axios(过于常见);Buffer、crypto(到处都有合法用途);单独使用 process.env(需要指定具体的环境变量名)。

字符串选择

价值排序: 互斥体名称最有价值,C2 路径次之,错误消息再次。堆栈字符串几乎总是唯一的。如果需要超过 6 个字符串,那就是过拟合了。

出现以下任一情况时,舍弃候选字符串:

测试失败原因替代做法
少于 4 字节不具备原子性找一个更长的字符串
重复字节(0000、9090)原子性弱添加周边上下文
API 名称(VirtualAlloc、CreateRemoteThread)每个加壳程序和安装程序都会调用使用调用位置的十六进制模式,加上唯一标记
出现在 Windows 系统文件中必然产生误报找一个特定于该家族的内容
常见路径(C:\Windows\、cmd.exe)无处不在找一个特定于恶意软件的路径
出现在其他恶意软件家族中无法识别这个家族与家族特定标记组合

剩下的内容——该家族独有的内容——才是规则应当依赖的依据。

选择字符串类型
需求使用
精确的 ASCII/Unicode 文本$s = "MutexName" ascii wide
特定字节序列$h = { 4D 5A 90 00 }
带有变化的字节序列十六进制通配符:{ 4D 5A ?? ?? 50 45 }
具有结构的模式(URL、路径)有界正则表达式:/https:\/\/[a-z]{5,20}\.onion/
未知编码(XOR、base64)修饰符:$s = "config" xor(0x00-0xFF)

**修饰符使用原则:**切勿臆测使用 nocase 或 wide,只有在有确凿证据表明大小写或编码会因样本而异时才使用。nocase 会使原子生成量翻倍;wide 会使字符串匹配量翻倍。“如果没有明确的理由使用这些修饰符,就不要使用”——Kaspersky Applied YARA。

条件设计

短路顺序:filesize <、魔数、字符串、模块。如果条件超过 5 行,就拆分成多条规则。

all of 与 any of
情况使用
字符串各自都特定于该恶意软件any of them——单独出现时各自都可疑
字符串很常见,但组合起来很可疑all of them——要求完整模式
字符串的置信度不同分组:all of ($core_*) and any of ($variant_*)
出现误报收紧条件:any → all,增加更多必需字符串

**来自生产环境的经验:**使用 any of ($network_*) 的规则,如果字符串中包含 fetch、axios 和 http,就会匹配几乎所有 Web 应用。改为要求凭据路径、网络调用和数据外传目的地同时出现后,误报便消除了。

按置信度分组

不同类型的指标权重不同——C2 域名可能具有决定性,而库导入则需要佐证。按前缀分组,可以表达不同级别的要求:

strings:
    $a1 = "SRWebSocket" ascii            // Category A: library indicators
    $a2 = "SocketRocket" ascii
    $b1 = "SSH tunnel" ascii             // Category B: behavioral
    $b2 = "keylogger" ascii nocase
    $c1 = /https:\/\/[a-z0-9]{8,16}\.onion/   // Category C: C2

condition:
    filesize < 10MB and
    any of ($a*) and any of ($b*)        // Evidence from BOTH categories
模块与字节检查
需求使用
imphash、rich header、authenticodePE 模块——难以复现的复杂检查
魔数或简单偏移uint16/uint32——速度更快,无模块开销
节名称/大小PE 模块,但要把魔数筛选放在最前面
Chrome 扩展权限crx 模块——字符串解析很脆弱
LNK 目标路径lnk 模块——格式很复杂

“避免使用 magic 模块——改用明确的十六进制检查”——Neo23x0。将此原则推广开来:如果 uint32() 能完成任务,就不要加载模块。

性能
  • **正则表达式必须以至少 4 字节的字面量为锚点。**没有锚点时,它会在每个文件偏移处进行计算,造成灾难性影响。写成 /mshta\.exe http:\/\/.../,而不是 /http:\/\/.../。如果无法设置锚点,就使用带通配符的十六进制模式。
  • 为每个正则量词设定边界——使用 .{0,30},绝不使用 .*。无界正则表达式既会严重影响性能,也会导致内存激增。
  • 用 filesize 限制循环范围——filesize < 100KB and for all i in (1..#a) : ...。在大文件中,无界的 #a 可能达到数千。
  • 字节固定时,优先使用十六进制而非正则表达式。

编写前:样本是否经过加壳?

信号应对措施
熵 > 7.0可能经过加壳 — 先找到未加壳的层
可读字符串很少或没有可能经过加壳 — 使用熵、PE 结构或加壳器特征
检测到 UPX/MPRESS/自定义加壳器针对解壳后的载荷,或直接检测加壳器本身
存在可读字符串继续使用基于字符串的检测

不要针对加壳层编写规则。 加壳方式会变,载荷不会变。

字符串检测失效时,转而分析结构

如果提取结果只有 API 名称和通用路径:

可用信号用途
高熵区段对特定区段使用 math.entropy()
异常的导入模式使用 pe.imphash() 进行导入哈希聚类
PE 结构异常区段名称、大小、特征
存在元数据版本信息、时间戳、资源
没有独特特征仅靠 YARA 可能无法检测此样本

“可以尝试利用其他文件属性,例如元数据、熵、导入哈希或其他保持不变的数据。” — Kaspersky Applied YARA 培训

调试误报

  1. 哪个字符串匹配了? — yr scan -s rule.yar false_positive.exe
  2. 是否位于合法库中? — 添加 not $fp_vendor_string 排除条件
  3. 是否为常见的开发模式? — 换成更具体的字符串
  4. 是否有多个通用字符串同时匹配? — 收紧规则,要求全部匹配,并添加一个独特标记
  5. 恶意软件是否使用了常见技术? — 针对其具体实现细节,而非该技术本身
何时放弃当前方法
  • 提取结果只有 API 名称和路径 → 转而分析结构
  • 找不到 3 个独特字符串 → 样本可能经过加壳;针对解壳后的版本,或检测加壳器
  • 规则匹配到良性文件 → 匹配 1-2 个:调查并收紧规则;匹配 3-5 个:寻找其他指标;匹配 6 个以上:从头开始
  • 优化后性能仍然很差 → 架构存在问题;拆分为专用规则,或添加严格的预过滤条件
  • 难以写清楚规则描述 → 规则太模糊。如果无法解释它会捕获什么,就说明它捕获的内容太多

应当摒弃的自我安慰

发现自己有以下想法时,请停下来重新考虑。

自我安慰专家回应
“这个通用字符串足够独特” / “这个十六进制模式很独特”在一个样本中独特 ≠ 在整个生态系统中独特。用良性文件集进行测试;你的直觉是错的。
“yarGen 给了我这些字符串”yarGen 只会提供建议,验证工作要由你完成。逐一手动检查 — 预计会舍弃 80%。
“它能匹配我的 10 个样本”10 个样本 ≠ 可用于生产环境。使用良性文件语料库。
“用一条规则捕获所有变体”会导致误报泛滥。针对特定家族。
“出现误报后我再让规则更具体” / “之后再添加条件”一开始就编写严格的规则。部署薄弱规则造成的损害已经无法挽回,误报会损害信任。
“这只是用于狩猎”狩猎规则会变成检测规则,质量标准相同。
“API 名称说明它是恶意的”合法软件也会使用相同的 API。需要行为上下文。
“这些常见字符串用 any of them 没问题”常见字符串 + any = 误报泛滥。仅当每个字符串都独特时,才使用 any of。
“这个正则表达式已经足够具体”/fetch.*token/ 会匹配所有身份验证代码。添加对外传目的地的要求。
“我会用 .* 增加灵活性”不受限制的正则表达式会导致性能灾难和内存激增。使用 .{0,30}。
“JavaScript 看起来很干净”攻击者会通过注入污染合法代码。检查 eval+decode 链。
“性能不重要”一条慢规则会拖慢整个规则集。优化原子模式。
“我到处都用 --relaxed-re-syntax”这会掩盖真正的错误。应修复正则表达式,而不是隐藏问题。
“PEiD 规则仍然有效”已经过时。32 位加壳器已无关紧要。

工具包

工具用途
yr CLIyr check(验证)、yr fmt(格式化)、yr scan -s(扫描并显示字符串)、yr dump -m pe(检查结构)
yarGen提取候选字符串:yarGen.py -m samples/ --excludegood
FLOSS提取混淆字符串/栈字符串:floss sample.exe —— yarGen 没有提取结果时使用
signature-base学习高质量示例
YARA-CI部署前测试良性软件语料库

掌握这五种工具即可。不要被工具目录分散注意力。

开发周期:

yr check rule.yar                                   # syntax, with precise line numbers
yr fmt -w rule.yar                                  # standardize formatting
yr dump -m pe sample.exe --output-format yaml       # inspect structure, no dummy rule needed
time yr scan -s rule.yar corpus/                    # scan with timing

在调查有哪些模块字段可用、调试模块条件为何未匹配,或在编写规则之前探索新模块(crx、lnk、dotnet)时,请使用 yr dump。YARA-X 的错误消息会提供精确的源代码位置——如果 yr check 提示第 15 行,那么问题就在第 15 行。

受版本限制的功能: private $helper = "pattern" 会进行匹配,但不会出现在输出中(v1.3.0+);// suppress: slow_pattern 可在行内忽略特定警告(v1.4.0+);filesize < 10_000_000 支持数字下划线(v1.5.0+)。$_unused 也可忽略未使用字符串警告。

Chrome 扩展分析(crx 模块)

需要 YARA-X v1.5.0+;使用 permhash() 则需要 v1.11.0+。

关键 API: crx.is_crx、crx.permissions、crx.permhash() 危险信号: nativeMessaging + downloads、debugger 权限、针对 <all_urls> 的内容脚本

import "crx"

rule SUSP_CRX_HighRiskPerms {
    condition:
        crx.is_crx and
        for any perm in crx.permissions : (perm == "debugger")
}

完整 API、权限风险评估和规则示例,请参阅 crx-module.md。

Android DEX 分析(dex 模块)

需要 YARA-X v1.11.0+。与旧版 YARA 的 dex 模块不兼容——API 完全不同。

关键 API: dex.is_dex、dex.contains_class()、dex.contains_method()、dex.contains_string() 危险信号: 单字母类名(混淆)、DexClassLoader 反射、加密资源

import "dex"

rule SUSP_DEX_DynamicLoading {
    condition:
        dex.is_dex and
        dex.contains_class("Ldalvik/system/DexClassLoader;")
}

完整 API、混淆检测和规则示例,请参阅 dex-module.md。

从旧版 YARA 迁移

99% 的规则兼容,但验证更加严格:

yr check --relaxed-re-syntax rules/   # identify issues
# fix each one, then verify without relaxed mode:
yr check rules/
问题旧版YARA-X 修复方式
正则表达式中的字面量 {/{//\{/
无效转义\R 会被静默视为字面量\\R 或 R
Base64 字符串任意长度至少需要 3 个字符
负索引@a[-1]@a[#a - 1]
重复修饰符允许删除重复项

--relaxed-re-syntax 是诊断手段,不是最终方案。请修复正则表达式。

命名和元数据

{CATEGORY}_{PLATFORM}_{FAMILY}_{VARIANT}_{DATE}      e.g. MAL_Win_Emotet_Loader_Jan25

类别: MAL_(恶意软件)、HKTL_(黑客工具)、WEBSHELL_、EXPL_、SUSP_(可疑)、GEN_(通用)。平台: Win_、Lnx_、Mac_、Android_、CRX_。

每条规则都需要包含 description(以 "Detects" 开头)、author、reference 和 date:

meta:
    description = "Detects Example malware via unique mutex and C2 path"
    author = "Your Name <[email protected]>"
    reference = "https://example.com/analysis"
    date = "2025-01-29"

完整规范请参阅 style-guide.md。

工作流

  1. 收集样本 — 多个样本;单样本规则很脆弱
  2. 提取候选项 — yarGen -m samples/ --excludegood
  3. 验证质量 — 应用字符串筛选测试;预计会舍弃 yarGen 输出的 80%
  4. 编写规则 — 元数据要完整,先执行开销较低的检查
  5. 检查并测试 — yr check、yr fmt、检查脚本
  6. 良性文件验证 — VirusTotal 样本库或本地干净文件
  7. 部署 — 补全元数据,然后监控误报(FP)

过程中的质量信号:规则匹配不到 50% 的已知变种,说明范围过窄;若匹配到良性文件,说明范围过宽。

审查他人编写的规则 — 先运行两个脚本,再目视阅读规则,并引用它们输出的代码:

uv run "<resolved-yara-lint-path>" suspect.yar      # style, metadata, YARA-X compatibility
uv run "<resolved-atom-analyzer-path>" suspect.yar  # atom quality per string

快捷用法:"<resolved-review-path>" suspect.yar(规则文件或目录) 会在一次调用中运行 yr check、yr fmt --check、检查脚本和原子分析器, 并打印一个 JSON 对象,{"target": ..., "checks": {"yr_check", "yr_format", "lint", "atoms"}},其中每项都包含 status(工具的退出代码)和 output。 所有检查均通过时退出码为 0,任一检查失败时为 1,输入缺失、为空 或无法读取时为 2(未检查任何内容)。与单独运行脚本时一样,准确引用 checks.lint.output 中的代码。

这些工具会捕获机械性问题——短字符串、易导致 FP 的子串、无界量词、将高开销项放在低开销项之前——让你能专注于它们无法判断的问题:这些字符串是否能识别这个家族,以及条件是否可能仅凭通用字符串触发。按代码(E002、W009)报告发现的问题,方便作者在 style-guide.md 中查找。

验证工作流请参阅 testing.md,完整的分步指南请参阅 rule-development.md。

常见错误

错误错误示例正确示例
将 API 名称用作指标"VirtualAlloc"调用位置的十六进制模式 + 独特的互斥锁
无界正则表达式/https?:\/\/.*//https?:\/\/[a-z0-9]{8,12}\.onion/
缺少文件类型筛选先检查 pe.imports(...)先检查 uint16(0) == 0x5A4D and filesize < 10MB
字符串过短"abc"(3 字节)"abcdef"(4 字节或以上)
未转义大括号(YARA-X)/config{key}//config\{key\}/
魔数的字节序错误uint32(0) == 0xCAFEBABEuint32be(0) == 0xCAFEBABE

质量检查清单

部署任何规则前:

  • 名称遵循 {CATEGORY}_{PLATFORM}_{FAMILY}_{VARIANT}_{DATE}
  • 描述以 "Detects" 开头,并说明检测对象和检测方式
  • 包含所有必需的元数据(作者、参考资料、日期)
  • 字符串具有独特性——不是 API 名称、常见路径或格式字符串
  • 所有字符串长度均为 4 字节或以上,且原子潜力良好
  • Base64 修饰符仅用于包含 3 个或更多字符的字符串
  • 正则表达式有界、以字面量为锚点,且 { 已转义
  • 条件从低开销检查开始(文件大小、魔数)
  • 已根据已知良性样本验证魔数字节常量
  • 规则匹配所有目标样本
  • 规则在良性文件样本库中零匹配
  • yr check 和 yr fmt --check 通过
  • 检查脚本运行通过,且无错误
  • 已完成同行评审

脚本

uv run "<resolved-yara-lint-path>" rule.yar      # validate style/metadata
uv run "<resolved-atom-analyzer-path>" rule.yar  # check string quality
"<resolved-review-path>" rule.yar                # all four checks, one JSON result

详细的脚本文档请参阅 README.md。

延伸阅读

主题文档
命名和元数据约定style-guide.md
性能和原子优化performance.md
字符串类型和判定strings.md
测试和验证testing.md
Chrome 扩展模块(crx)crx-module.md
Android DEX 模块(dex)dex-module.md
完整的规则开发流程rule-development.md

examples/ 目录包含真实且注明来源的规则,值得在编写自己的规则前阅读:

示例展示内容来源
MAL_Win_Remcos_Jan25.yarPE 恶意软件:分级字符串计数、每个家族包含多条规则Elastic Security
MAL_Mac_ProtonRAT_Jan25.yarmacOS:Mach-O 魔数、多类别分组Airbnb BinaryAlert
MAL_NPM_SupplyChain_Jan25.yarnpm 供应链:真实攻击模式、ERC-20 选择器Stairwell Research
SUSP_JS_Obfuscation_Jan25.yarJavaScript:混淆器检测、基于密度的匹配imp0rtp3, Nils Kuhnert
SUSP_CRX_SuspiciousPermissions.yarChrome 扩展:crx 模块、权限教育用途

可供学习的规则仓库: Neo23x0/signature-base(17,000 多条生产规则)、elastic/protections-artifacts(经过端点测试)、imp0rtp3/js-yara-rules(JavaScript)、InQuest/awesome-yara(精选索引)。

指南: YARA Style Guide 和 YARA Performance Guidelines(Neo23x0),YARA-X 文档。

macOS 特定内容: Apple 自己的生产规则位于 /System/Library/CoreServices/XProtect.bundle/;objective-see 发布 macOS 恶意软件研究和样本。

评论

支持 Markdown