YARA 规则编写实战——从样本到检测规则

引言:从"看懂样本"到"拦住家族"的最后一公里

在恶意软件分析的完整链路中,YARA 规则产出是把分析成果转化为可复用检测资产的关键一步 。样本静态分析给了你行为画像、动态分析给了你 IOC、逆向工程给了你内部机制------但这些成果如果只停留在内部报告,一旦下次样本换了哈希、换了壳、换了字符串,你的情报就"过期"了。YARA 规则的真正价值,是把"某个样本"的特征抽象成"某个家族"的模式------让一条规则在样本库、终端、网关、SIEM 里长期服役,哪怕攻击者重编译、换 C2、小改字符串,规则依然能命中。

但社区里大量流传的 YARA 教程存在一个共同的局限:要么只讲语法,要么只讲工具 。语法背得再熟,遇到真实样本依然不知道哪条字符串该放进规则、哪条该丢掉;工具用得再溜,生成的规则扔进 VT 扫一遍全是误报。真正决定一条规则能否服役于生产环境的,是三件朴素的事 :字符串选得准不准、条件平衡得好不好、规则跑得快不快。第一条规则是最难写的,写好它是把样本分析"变现"的过程;后面几十条只是复制这条曲线

本文按"样本 → 字符串 → 条件 → 测试 → 迭代 → 沉淀 "的主线展开,分八个部分:方法论 → 核心语法 → PE 模块进阶 → 完整实战案例(三个规则从 0 到 1)→ 误报治理 → 自动化工具链 yarGen → 规则库管理 → 学习路径。读完之后,你应当能独立完成一次"从拿到样本到提交规则"的完整闭环,并知道什么时候写规则、什么时候不该写规则。

第一章:转化方法论------一条好规则的"四个层次"

在写第一行代码之前,必须先明确"什么样的 YARA 规则才叫好"。社区对"好规则"的定义在逐步收敛,核心是四个层次的能力:

层次 含义 典型反例
准确 匹配已知恶意样本,零误报 一条规则把 Chrome.exe 也扫出来
召回 匹配同家族变种,少量漏报 只匹配到一个特定 SHA256 才算赢------不如直接用哈希
性能 大规模扫描(数百万文件)时 CPU/时间可控 一条规则把整个磁盘扫了 4 小时
可读 三个月后你自己还能看懂这条规则为什么这么写 $s1 = "abc" 没有任何注释,无法复盘

1.1 规则的两种"用途"决定编写策略

在动手之前,先问自己:**这条规则是用来"定性"还是用来"狩猎"?**两种用途对应完全不同的编写策略。

用途 A:狩猎型规则------目标是覆盖面广、误报可以接受,用于在大量样本里"扫一扫、看看到底有什么"。

  • 策略 :条件宽松,字符串数量可以少,允许 any of them
  • 典型输出:一批匹配结果,人工再过滤;
  • 生命周期 :短(活动结束就废弃)。
    用途 B:定性型规则 ------目标是精确匹配已知家族、零误报,用于生产环境(SIEM、EDR、网关)持续检测。
  • 策略:条件严格,字符串要"独特+难改",必须有 filesize/PE 结构等"硬约束";
  • 典型输出 :一条匹配即告警,不允许分析师再人工过滤
  • 生命周期 :长(可能服役数年)。
    大量规则的失败,源于作者没有想清楚自己在写哪一种。一条狩猎型规则直接扔进生产环境,一定会触发误报风暴;一条定性型规则条件太松,新变种一来就漏。

1.2 什么样的样本"值得写规则"

不是所有样本都值得写规则。社区有共识:以下情况优先写:

  • APT 样本:复杂、定向、家族特征独特,规则价值最高;
  • 新型家族:VT 检出率低,公开规则库还没有,先发优势明显;
  • 本地化定制样本:企业内网特有样本,外部规则库不会覆盖;
  • 单一哈希失效的场景 :攻击者使用同 Builder 产出多变种,哈希防不住。
    以下情况不建议写规则
  • 已广泛流行的家族(Emotet、AgentTesla):社区规则库(Reversing Labs、Valhalla、Yara-Rules)已经有数百条优质规则,重写毫无意义;
  • 单次攻击的"一次性"样本:没有家族延续,规则很快失效;
  • 纯哈希匹配场景:变种极少,直接用 SHA256 + VT 看板即可。

1.3 规则的三种"来源"(家族 / 行为 / 工具)

YARA 规则不一定要针对"家族"------针对行为的规则往往比针对家族的更耐打。

规则类型 目标 典型字符串 稳定性
家族规则 特定恶意软件家族 Mutex、PDB 路径、硬编码 C2、Builder 水印 中(攻击者可换 Builder)
行为规则 特定恶意行为组合 勒索软件的 shadowcopy + 加密扩展名组合 高(行为比代码更难改)
工具规则 特定攻击工具链 Cobalt Strike、Mimikatz、Malleable Profile 特征
编写优先级家族规则 > 行为规则 > 工具规则------因为家族规则的"精度"最高,行为规则"召回"最好,工具规则便于对攻击基础设施做归因。

第二章:核心语法速通------你需要掌握的"最小集合"

YARA 语法酷似 C 语言,但完整语法有几百页文档。写生产规则,只需掌握"最小集合"------本节按"高频使用"排列,从必会到进阶。

2.1 规则的四段式骨架

yara 复制代码
import "pe"                       // 可选:导入模块
import "math"
import "hash"
rule Rule_Identifier {            // 规则名,≤128 字符,区分大小写
    meta:                         // 元数据(可选,强烈建议写全)
        author = "analyst_name"
        date = "2026-09-03"
        description = "Detects XXX family based on unique strings + PE structure"
        family = "XXX"
        reference = "https://..."
        hash = "sha256_of_reference_sample"
        license = "Apache-2.0"
    strings:                      // 字符串定义(可选)
        $s1 = "unique_string" ascii
        $s2 = { 4D 5A 90 00 }     // 十六进制
        $s3 = /regex_pattern/i    // 正则
    condition:                    // 条件(必需)
        uint16(0) == 0x5A4D and 2 of ($s*)
}

关键要点

  • 规则名:字符+下划线,不能以数字开头,≤128 字符,必须唯一;
  • 元数据 :不参与匹配,但在规则命中时随报告返回,是规则可读性的唯一载体
  • 字符串定义区 :以 $ 开头的标识符 + 值;
  • 条件区:必须返回布尔值。

2.2 字符串的三种类型

文本字符串、十六进制字符串、正则表达式 ------三种各有用途,生产规则建议至少混用两种

文本字符串(最常用):

yara 复制代码
$s1 = "This program cannot"                 // 默认 ASCII
$s2 = "注册表路径" wide                      // UTF-16LE 编码(Windows 宽字符)
$s3 = "CaSe insensitive" nocase             // 忽略大小写
$s4 = "unique_phrase" fullword              // 前后不能有字母/数字
$s5 = "hidden_data" xor                     // 自动尝试所有单字节 XOR (0x01-0xFF)
$s6 = "hidden_data" xor(0x01-0x3F)          // 限定 XOR 范围,提速
$s7 = "base64encoded" base64                // 匹配 Base64 编码后的形态
$s8 = "base64encoded" base64wide            // Base64 + UTF-16LE

十六进制字符串(精准匹配二进制模式):

yara 复制代码
$r1 = { 4D 5A 90 00 }                       // 精确字节序列
$r2 = { E8 ?? ?? ?? ?? 68 ?? ?? ?? ?? }     // 通配符(? = 任意字节)
$r3 = { 4D 5A [3-10] 50 45 00 00 }          // 跳转 [n-m],匹配 3-10 个任意字节
$r4 = { 68 ( 61 | 62 | 63 ) 20 }            // 或运算,匹配 61/62/63 任一

正则表达式(灵活但性能开销大):

yara 复制代码
$re1 = /https?:\/\/[a-z0-9\-\.]+\.(xyz|top|buzz)\/[a-z]{8}/    // C2 URL 模式
$re2 = /[A-Za-z0-9+\/]{50,}={0,2}/                              // Base64 长块
$re3 = /cmd\.exe\s+\/c\s+/i                                      // 命令行模式

关键陷阱正则表达式必须有"锚点"(atom) 。YARA 引擎会从字符串中挑出 4 字节左右的"原子"喂给 Aho-Corasick 自动机做初筛------没有良好原子的正则(如 /w.*d//[0-9]+n/)会导致扫描性能崩塌

2.3 条件表达式的"高频组合"

条件区是规则的"灵魂" ------它决定了"多少证据才算命中"。以下是 90% 规则用到的"高频组合":

基础逻辑

yara 复制代码
condition: $s1 and $s2                          // 都匹配
condition: $s1 or $s2                           // 至少一个
condition: not $s3                              // 不匹配
condition: any of ($s*)                         // 任意 $s 开头的字符串
condition: all of ($s*)                         // 所有 $s 开头的字符串
condition: 2 of ($s1, $s2, $s3, $s4)            // 至少 2 个
condition: 1 of them                            // 任意一个(匿名用)

位置限定(减少误报的利器):

yara 复制代码
condition: $s1 at 0                             // 字符串必须在偏移 0(如 MZ 头)
condition: $s1 in (0..1024)                     // 字符串必须在文件前 1KB 内
condition: #s1 > 3                              // 字符串出现次数 > 3 次
condition: @s1[1] < 2048                        // 字符串第一次出现在 2KB 内

文件属性

yara 复制代码
condition: filesize < 2MB                       // 文件大小限制
condition: uint16(0) == 0x5A4D                  // MZ 头(PE 文件)
condition: uint32(0) == 0x464C457F              // ELF 头
condition: uint32(0) == 0xfeedface              // Mach-O 头

for 循环(高级组合逻辑):

yara 复制代码
// 所有 $a 的出现位置都在文件前 100 字节内
condition: for all i in (1..#a) : ( @a[i] < 100 )
// 至少有 2 个字符串出现在入口点附近
condition: for 2 of ($a*) : ( $ in (entrypoint..entrypoint+1024) )
// PE 模块:任意节区名为 ".text"
condition: for any section in pe.sections : ( section.name == ".text" )

引用其他规则(复合规则):

yara 复制代码
rule base_filter {
    condition: uint16(0) == 0x5A4D and filesize < 1MB
}
rule composite_rule {
    condition: base_filter and $malicious_string
}

2.4 字符串修饰符的"选择原则"

修饰符不是"越多越好"------每一个修饰符都增加匹配范围,也增加误报概率。

修饰符 何时使用 何时避免
ascii 字符串确定是 ASCII 编码 任何 Windows API 路径/URL(它们通常是 UTF-16LE)
wide 字符串是 Windows 宽字符(API 路径、Mutex 名) 纯 ASCII 的 C2 URL(通常是窄字符)
nocase 字符串大小写可能变化(如用户输入) 硬编码常量(如 PDB 路径、Builder 标识)
fullword 字符串是完整单词(如 API 名 CreateFile 字符串可能是更长文本的子串
xor 样本用单字节 XOR 加密字符串 字符串未被加密(会大幅增加性能开销)
base64 样本用 Base64 编码数据 数据未被编码(会爆炸性增加匹配数量)
private 字符串作为"内部辅助"不输出 字符串本身是关键指标,需要出现在报告中

一条经验法则每次加一个修饰符,都跑一遍"好样本库"(见第五章)------确保新加的修饰符不会让规则误报暴涨。

第三章:PE 模块进阶------超越字符串的"结构级"检测

字符串是最容易被绕过的 ------攻击者换一个 Mutex、改一个 URL,你的规则就废了。PE 模块让你能针对"结构"写规则------结构比字符串更稳定。

3.1 PE 模块的核心属性

yara 复制代码
import "pe"
// 机器架构
condition: pe.machine == pe.MACHINE_AMD64        // 64位
condition: pe.machine == pe.MACHINE_I386         // 32位
// 子系统
condition: pe.subsystem == pe.SUBSYSTEM_WINDOWS_GUI       // GUI 程序
condition: pe.subsystem == pe.SUBSYSTEM_WINDOWS_CUI       // 控制台程序
// 编译时间戳
condition: pe.timestamp >= 1689206400             // 2023-07-13 之后编译
// PE 特性位图
condition: pe.characteristics & pe.DLL            // 是 DLL
condition: pe.characteristics & pe.EXECUTABLE_IMAGE // 是可执行文件
// 节区
condition: pe.number_of_sections == 3             // 节区数
condition: pe.sections[0].name == ".text"         // 第一个节区名
// 导入/导出
condition: pe.number_of_imports > 20
condition: pe.exports("CPlApplet")                // 导出特定函数
// 版本信息
condition: pe.version_info["CompanyName"] contains "Microsoft"

3.2 Imphash:导入表的"家族指纹"

Imphash(导入表哈希)是 YARA 家族聚类最有效的工具之一 ------同一家族用同一 Builder 产出的样本,即使代码不同,导入表往往相同,Imphash 完全一致

yara 复制代码
import "pe"
import "hash"
// BlackBerry 发布的 Chaos/Yashma 勒索软件规则(实战案例)
import "pe"
rule Mal_Win32_ChaosRansomware_2022 {
    meta:
        author = "BlackBerry Threat Research"
        date = "2022-05-10"
        family = "Chaos/Yashma"
    strings:
        $x1 = "Encrypt" ascii wide
        $x2 = "(?:[13]{1}[a-km-zA-HJ-NP-Z1-9]{26,33}|bc1[a-z0-9]{39,59})" ascii wide
        $z0 = "deleteShadowCopies" ascii wide
        $z1 = "shadowcopy" ascii wide
    condition:
        uint16(0) == 0x5a4d and
        filesize < 35KB and
        pe.imphash() == "f34d5f2d4577ed6d9ceec516c1f5a744" and
        pe.number_of_sections == 3 and
        all of ($x*) and 1 of ($z*)
}

Imphash 的使用策略

  • 组合pe.imphash() 单独使用太"具体"(变种改导入就漏),应与字符串组合
  • 获取:pefile、PEStudio、VirusTotal、MalwareBazaar 都能查到样本的 imphash;
  • 注意:攻击者改一个导入顺序就能改变 imphash,所以它是"聚类线索"而非"身份证明"。

3.3 Rich Header Hash:编译器指纹

Rich Header 是微软链接器插入的未公开结构,包含编译工具链信息------它的哈希极难伪造,能用来归因。

yara 复制代码
import "pe"
import "hash"
rule APT42_CHAIRSMACK_PE_Metadata {
    meta:
        author = "your_name"
        description = "Detects samples based on unique imphash + Rich Header hash"
        reference = "https://mandiant.com/resources/blog/apt42-charms-cons-compromises"
    condition:
        pe.imphash() == "72f60d7f4ce22db4506547ad555ea0b1" or
        hash.md5(pe.rich_signature.clear_data) == "c0de41e45352714500771d43f0d8c4c3"
}

3.4 节区与熵值的"加壳检测"

结构化的"加壳检测"规则,用于发现"可疑的加壳 PE":

yara 复制代码
import "pe"
import "math"
rule Suspect_Packed_PE_High_Entropy {
    meta:
        author = "your_name"
        description = "Flags small PE files with high-entropy sections"
    condition:
        pe.is_pe and
        filesize < 500KB and
        pe.number_of_sections <= 4 and
        math.entropy(0, filesize) > 7.2
}

熵值判读 :正常代码节区熵值 5~6.5,>7.0 强烈疑似加壳>7.5 几乎必然加密

第四章:完整实战案例------从样本到规则的全过程

现在把所有知识点串起来,用三个递进式案例演示"从拿到样本到提交规则"的完整流程。

案例一:基于字符串+PE 结构的"家族规则"

背景 :拿到一个可疑样本 sample.exe(SHA256: a3f8c92b...),静态分析已确认属于 AgentTesla 家族变种,需要产出一条生产可用的定性规则。

Step 1:提取候选字符串

用 PEStudio、FLOSS、strings 提取全部字符串,按"独特性"和"稳定性"分类

text 复制代码
【高独特性 + 高稳定性】(优先候选)
  - PDB 路径:C:\Users\dev\source\repos\NewAgent\obj\Release\NewAgent.pdb
  - Mutex 名:Global\{4D51A0B5-...}
  - 硬编码 SMTP 域:smtp.qiye.xxx.com:465
  
【中独特性 + 中稳定性】(候选)
  - C2 URL:hxxp://mail.cdn-metrics.example.top/upload.php
  - 加密密钥标识:AES_KEY_2026_XX
  
【低独特性】(丢弃)
  - kernel32.dll、CreateFileW 等通用 API
  - "This program cannot be run in DOS mode"
  - "Mozilla/5.0 ..."(所有浏览器样本都有)

判断"独特性"的实用方法把字符串扔进 Google / VirusTotal / 良性样本库搜一下 ------搜出 10 个以上结果,这条字符串就没价值。

Step 2:从 PE 结构提取"硬约束"

用 PEStudio / pefile 提取:

  • filesize: 248KB(限定 < 1MB)
  • PE 头 : uint16(0) == 0x5A4D
  • 节区数: 4
  • imphash : a1b2c3d4e5f6...
  • 编译时间 : 2026-08-24
    Step 3:v1 规则(草稿)
yara 复制代码
import "pe"
rule AgentTesla_Variant_2026_09 {
    meta:
        author = "your_name"
        date = "2026-09-03"
        description = "Detects AgentTesla variant based on PDB path + mutex + PE structure"
        family = "AgentTesla"
        hash = "a3f8c92b..."
    strings:
        $pdb = "NewAgent\\\\obj\\\\Release" ascii         // PDB 路径片段
        $mutex = "{4D51A0B5-" ascii wide                   // Mutex 前缀
        $smtp = "smtp.qiye" ascii wide                     // SMTP 域名片段
        $mz = { 4D 5A 90 00 }                              // PE 头
    condition:
        uint16(0) == 0x5A4D and
        filesize < 1MB and
        2 of ($pdb, $mutex, $smtp)
}

Step 4:v1 测试

bash 复制代码
# 对已知恶意样本扫描(应命中)
yara rule.yar sample.exe
yara -s rule.yar sample.exe                          # 显示匹配的字符串
# 对"好样本库"扫描(不应命中)
yara -r rule.yar /opt/goodware/

测试结果假设

  • 恶意样本:命中 ✓
  • 好样本库 10000 个文件:命中 3 个NewAgent.pdb 字段出现在某个学习资料里)------需要迭代
    Step 5:v2 迭代(收紧条件)
    发现 $pdb 字符串过于宽泛(obj\Release 在任何 VS 项目的 PDB 路径都可能出现),需要更具体
yara 复制代码
import "pe"
rule AgentTesla_Variant_2026_09 {
    meta:
        author = "your_name"
        date = "2026-09-03"
        description = "Detects AgentTesla variant (2026-09 campaign)"
        family = "AgentTesla"
        version = "2.0"
        hash = "a3f8c92b..."
    strings:
        $pdb = "NewAgent\\\\obj\\\\Release\\\\NewAgent.pdb" ascii    // 完整路径
        $mutex = "Global\\\\{4D51A0B5-" ascii wide                   // 完整 Mutex 前缀
        $smtp = "smtp.qiye" ascii wide
        $mz = { 4D 5A 90 00 }
    condition:
        uint16(0) == 0x5A4D and
        filesize < 1MB and
        pe.number_of_sections == 4 and
        ( $mutex and $smtp ) or
        ( $pdb and $smtp )
}

重新测试 :好样本库零命中,恶意样本库 10/10 命中。规则达标

案例二:基于"行为组合"的"行为规则"

背景 :勒索软件变种众多,家族规则容易失效;写一条行为规则 ,专门匹配"勒索软件的典型行为组合"。

Step 1:定义"行为组合"

勒索软件的行为特征(可以独立于家族):

  • 有加密相关 API 字符串(AES、RSA、ChaCha20)
  • 有卷影删除字符串vssadminshadowcopy
  • 有勒索信相关字符串.encryptedREADME_FOR_DECRYPT
  • 有加密文件扩展名
    Step 2:编写行为规则
yara 复制代码
import "pe"
rule Ransomware_Behavioral_Indicators {
    meta:
        author = "your_name"
        date = "2026-09-03"
        description = "Detects ransomware behavioral combination (shadow copy deletion + encryption artifacts)"
        category = "ransomware"
        reference = "MITRE ATT&CK T1486, T1490"
    strings:
        // 加密相关
        $enc1 = "CryptEncrypt" ascii
        $enc2 = "CryptAcquireContext" ascii
        $enc3 = "ChaCha20" ascii nocase
        
        // 卷影删除
        $vss1 = "vssadmin.exe delete shadows" ascii
        $vss2 = "DeleteShadowCopies" ascii wide
        $vss3 = "SHADOWCOPY" ascii nocase
        
        // 勒索信
        $note1 = ".encrypted" ascii
        $note2 = "HOW_TO_DECRYPT" ascii nocase
        $note3 = "YOUR_FILES" ascii nocase
        
        // 钱包地址
        $btc = /[13][a-km-zA-HJ-NP-Z1-9]{27,34}/
        $xmr = /4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}/
        
        // PE 头
        $mz = { 4D 5A 90 00 }
    condition:
        uint16(0) == 0x5A4D and
        filesize < 5MB and
        // 行为组合:加密 + 卷影删除 + 勒索信(或加密 + 钱包地址)
        (
            (1 of ($enc*) and 1 of ($vss*) and 1 of ($note*)) or
            (2 of ($enc*) and 1 of ($btc, $xmr))
        )
}

这类规则的优势"行为"比"代码"更难伪造 ------攻击者可以换家族、换 Builder,但"勒索"这个行为本身不会变。缺点:误报率比家族规则高,需要配合 filesize 和 PE 结构收窄。

案例三:基于"工具指纹"的"工具规则"

背景 :Cobalt Strike Beacon 在野使用极广,写一条"工具指纹规则",用于狩猎 CS 流量。

yara 复制代码
import "pe"
rule Cobalt_Strike_Beacon_Indicators {
    meta:
        author = "your_name"
        date = "2026-09-03"
        description = "Detects Cobalt Strike Beacon artifacts (config paths, mutex patterns)"
        category = "tool"
        reference = "MITRE ATT&CK S0154"
    strings:
        // Malleable Profile 默认特征
        $c1 = "/submit.php" ascii
        $c2 = "IEX (New-Object Net.Webclient)" ascii
        $c3 = "%s (as %s\\\\%s)" ascii                 // beacons 输出格式
        $c4 = "AppData\\\\Roaming\\\\Microsoft\\\\" ascii wide
        
        // 配置解密标识
        $c5 = { 00 01 00 01 00 02 00 }                  // CS 4.x config magic
        
        // 无文件驻留相关
        $c6 = "CreateRemoteThread" ascii
        $c7 = "WriteProcessMemory" ascii
        
        // PE 结构
        $mz = { 4D 5A 90 00 }
    condition:
        uint16(0) == 0x5A4D and
        filesize < 5MB and
        (
            2 of ($c1, $c2, $c3, $c5) or
            ( $c6 and $c7 and 1 of ($c1, $c4) )
        )
}

工具规则的特殊价值同一个工具(如 CS)被多个 APT 组织使用------一条工具规则可以同时命中多个组织的攻击,是狩猎阶段的"高杠杆"资产。

第五章:误报治理------从"乱报警"到"零误报"的迭代循环

误报是 YARA 规则最大的"杀手" ------一条规则误报率高到 SOC 无法忍受,就会被管理员禁用;一旦被禁用,它就"死"了。据社区统计,68% 没有做过良性样本验证的规则,误报率超过 10%

5.1 建立你的"好样本库"(Goodware Corpus)

没有好样本库,就无法证明"零误报"。建议逐步建立以下分层:

text 复制代码
/opt/goodware/
├── windows_core/          # Windows 系统文件(C:\Windows\System32 完整拷贝)
├── common_apps/           # 常见应用(Chrome、Office、Adobe、微信、QQ)
├── dev_tools/             # 开发工具(VS、Python、Git、Node.js、JDK)
├── security_tools/        # 安全工具(Wireshark、Sysinternals、7-Zip)
├── compiler_artifacts/    # 各种编译器产出(MSVC、MinGW、PyInstaller 等)
└── your_company/          # 你所在公司的合法业务文件

关键要求数量级至少 10,000 个文件,覆盖所有"你会扫的文件类型"------比如你的规则只针对 PE,好样本库至少有 5,000 个 PE。

5.2 迭代循环:写规则 → 扫描 → 分析误报 → 修正

一条规则的诞生,通常经过 3~5 轮迭代

text 复制代码
【Round 1】写 v1 规则(基于已分析样本的字符串)
  ↓ 扫描好样本库 → 发现 30 个误报
  
【Round 2】分析误报,找出"字符串太通用"的原因
  - 可能是 API 名(CreateFile)
  - 可能是常见错误消息
  - 可能是 PDB 路径的通用部分(obj\Release)
  → 收紧字符串或加位置限定
  ↓ 扫描好样本库 → 发现 5 个误报
  
【Round 3】继续收紧
  - 加 filesize 限制
  - 加 pe.number_of_sections 限制
  - 加 imphash 限制
  ↓ 扫描好样本库 → 0 误报
  
【Round 4】扫恶意样本库(确认召回率)
  - 如果召回率 < 90%,可能条件太严
  - 放宽一些次要条件,重复 Round 2-3
  
【Round 5】终测 + 提交
  - 跑一遍完整的恶意样本库 + 好样本库
  - 记录"检出/误报"的数字进 meta
  - 提交到规则库

5.3 性能优化:让规则跑得"快"

YARA 性能的核心是"条件求值顺序" ------条件从左到右求值,一旦某项为 False 就跳过后续

性能金字塔(从快到慢):

层次 检查项 开销
1(最快) filesize 几乎为 0
2 uint16(0) == 0x5A4D / uint32(0) 极低
3 短十六进制字符串
4 文本字符串(含 good atoms)
5 长十六进制 + 通配符 中高
6(最慢) 复杂正则、PE 模块、for 循环、熵值计算
优化前后对比
yara 复制代码
// 慢:先算熵值再查 PE 头
condition: math.entropy(0, filesize) > 7.0 and uint16(0) == 0x5A4D
// 快:先查 PE 头(毫秒级),再算熵值
condition: uint16(0) == 0x5A4D and math.entropy(0, filesize) > 7.0

三条优化铁律

yara 复制代码
// 铁律 1:filesize 和 magic 放在最前
condition: uint16(0) == 0x5A4D and filesize < 2MB and ( ...复杂条件... )
// 铁律 2:避免通配符前缀(会让 atom 选择变差)
// 坏:{ ?? ?? ?? ?? 4D 5A 90 00 }
// 好:{ 4D 5A 90 00 ?? ?? ?? ?? }
// 铁律 3:避免无锚点正则
// 坏:/.*malware.*/        (无 atom,性能崩塌)
// 好:/malware_(\d{4})/    ("mala" 是 good atom)

5.4 避免"Pepper"(胡椒)问题的"三层验证"

社区经常提"avoid peppering" ------指的是过度使用通配符、宽泛条件导致规则对大量无关样本"撒胡椒面" 。避免 Pepper 的三层验证:

第一层:字符串层验证

bash 复制代码
# 把每条字符串扔进 VT 搜索
# 如果某条字符串命中了 > 10 个无关样本,这条字符串就是"胡椒"

第二层:规则层验证

bash 复制代码
# 对好样本库全量扫描
yara -r rule.yar /opt/goodware/
# 误报数 = 0 才能进入下一层

第三层:生态层验证

bash 复制代码
# 用 YARA-CI(VirusTotal)或 yaraQA 检查规则的"语法+结构+误报"
# yaraQA 会对规则打分(100 分制,误报/性能/结构问题都会扣分)

5.5 常见"坑点"清单

text 复制代码
【坑点 1】只匹配单个字符串(容易误报 + 容易被绕过)
   坏:$s1 = "malware_string" ascii nocase
   好:uint16(0) == 0x5A4D and $s1 and 2 of ($s*)
【坑点 2】没有 filesize 限制
   影响:扫描大文件时性能极差,甚至扫描内存 dump 时溢出
【坑点 3】通配符滥用
   坏:{ ?? ?? ?? ?? ?? ?? ?? ?? }
   后果:匹配几乎所有文件
【坑点 4】modifiers 加得过多
   $s = "hello" ascii wide nocase xor base64 fullword
   后果:匹配范围爆炸,误报率飙升
【坑点 5】正则无锚点
   坏:/.*password.*/
   后果:性能极差,且容易误报
【坑点 6】规则名不具描述性
   坏:rule rule1 { ... }
   好:rule AgentTesla_Variant_2026_09 { ... }
【坑点 7】meta 不完整
   后果:三个月后你自己都不知道这条规则是干嘛的
【坑点 8】硬编码的字符串没有注释
   坏:$s1 = "Xyz_9Ab2"       ← 为什么是它?
   好:$s1 = "Xyz_9Ab2" ascii  // unique mutex used by XXX family

第六章:自动化工具链------从"手工写"到"半自动"

手工写规则是对抗高级样本的"精工" ,但面对批量样本,自动化工具能显著提升效率。本节介绍 yarGen 系列工具。

6.1 yarGen:Florian Roth 的规则生成神器

yarGen 的核心原理 :从恶意样本中提取字符串,自动排除"良性软件库"中已有的字符串 ,剩下"独特字符串"用于生成规则。

安装与更新

bash 复制代码
# 克隆项目
git clone https://github.com/Neo23x0/yarGen
cd yarGen
# 安装依赖
pip3 install -r requirements.txt
# 首次使用前更新内置数据库(重要!会下载 goodware 字符串/opcode 库)
python3 yarGen.py --update

基础用法

bash 复制代码
# 从恶意样本目录生成规则(最简单)
python3 yarGen.py -m /path/to/malware/
# 排除良性字符串(重要!强烈推荐加)
python3 yarGen.py -m /path/to/malware/ --excludegood
# 指定输出
python3 yarGen.py -m /path/to/malware/ -o /tmp/rules.yar -a "your_name" -r "reference_url"
# 只取高分字符串(更严格)
python3 yarGen.py -m /path/to/malware/ -z 10 --score
# 排除 goodware 字符串 + 指定作者 + 输出
python3 yarGen.py -m /path/to/malware/ --excludegood -o output.yar \
    -a "analyst_name" -r "internal_case_ref"

关键参数说明

参数 说明 推荐值
-m 恶意样本目录 必填
--excludegood 排除良性样本中已有的字符串 必加
-z 最低字符串分数 10(生产规则)
-rc 最多字符串数 20
-o 输出文件 必填
-a 作者 你的 ID
-r 参考 情报来源
--nomagic 不加 magic 头检查 不推荐
--nofilesize 不加 filesize 限制 不推荐
yarGen 输出示例(生成的规则初稿):
yara 复制代码
rule CN_Actor_ToolKit_Sample_a3f8c {
    meta:
        author = "your_name"
        description = "Auto-generated rule for file a3f8c92b..."
        date = "2026-09-03"
        hash = "a3f8c92b..."
    strings:
        $s1 = "Global\\\\{4D51A0B5-" ascii wide
        $s2 = "smtp.qiye" ascii wide
        $s3 = "NewAgent\\\\obj\\\\Release" ascii
        $s4 = { 4D 5A 90 00 }
    condition:
        uint16(0) == 0x5A4D and 3 of them
}

yarGen 的局限它是"规则起点",不是"规则终点" 。生成的规则通常召回率不错但误报率中等必须经过第五章的迭代循环才算生产可用。

6.2 yarAnalyzer:批量规则的质量分析

当你手头有几十条规则时,需要工具帮你"批量分析"yarAnalyzer 能分析规则质量、找出重叠、评估复杂度。

bash 复制代码
python3 yarAnalyzer.py -p /path/to/rules/

6.3 其他工具

工具 用途
Loki 扫描器(基于 YARA 的 IOC 检测工具)
THOR 商业版扫描器(Nextron 出品)
Valhalla Nextron 的 YARA 规则订阅服务
yaraQA 规则质量评分工具
yara-cop Visual Studio Code 的 YARA 语法检查插件
YARA-CI (VirusTotal) 在线规则 CI(扫 NSRL 和 VT 良性库)
VarComparators 在线规则对比与聚类工具

第七章:规则库管理与部署------从"单条规则"到"作战资产"

一条规则是"原子",一个规则库是"作战体系" 。规则管理的核心是可追溯、可回滚、可分发

7.1 规则库的目录结构

text 复制代码
/opt/yara_rules/
├── meta/
│   ├── CHANGELOG.md
│   └── README.md
├── rules/
│   ├── apt/                    # APT 组织相关
│   │   ├── APT41_Sample1.yar
│   │   └── APT41_Sample2.yar
│   ├── malware/                # 已知恶意软件家族
│   │   ├── AgentTesla.yar
│   │   ├── CobaltStrike.yar
│   │   └── Ransomware_General.yar
│   ├── behavioral/             # 行为规则
│   │   ├── Packed_PE.yar
│   │   └── Suspicious_Strings.yar
│   ├── toolkit/                # 工具规则
│   │   ├── Mimikatz.yar
│   │   └── Metasploit.yar
│   ├── webshell/               # Webshell
│   │   ├── PHP_Webshell.yar
│   │   └── JSP_Memshell.yar
│   └── index.yar               # 索引文件(include 其他)
├── tests/
│   ├── goodware/               # 好样本库
│   └── malware/                # 已知恶意样本库
└── scripts/
    ├── validate_rules.sh       # 规则验证脚本
    └── deploy_rules.sh         # 部署脚本

index.yar 示例

yara 复制代码
include "rules/apt/APT41_Sample1.yar"
include "rules/malware/AgentTesla.yar"
include "rules/behavioral/Packed_PE.yar"

7.2 规则的版本管理与 Git 流程

规则必须进 Git------因为规则变更就是"检测策略变更",需要可追溯:

bash 复制代码
# 1. 规则变更进 Git
git checkout -b new_rule_agenttesla
vim rules/malware/AgentTesla.yar
git add rules/malware/AgentTesla.yar
git commit -m "Add AgentTesla v2 rule (reduced FP from 3 to 0 on 10k goodware corpus)"
# 2. 跑自动化验证(CI/CD)
#    - 语法检查
#    - 好样本库扫描(零误报)
#    - 恶意样本库扫描(召回率达标)
./scripts/validate_rules.sh
# 3. PR Review → Merge → 部署
git push origin new_rule_agenttesla

7.3 部署到终端与网关

规则部署的常见通道

部署位置 工具 频率
Linux 主机 YARA CLI + cron 每日
Windows 终端 Loki / THOR 每日
EDR 商业 EDR API 实时
网关/邮件 YARA-HI 或邮件网关规则 实时
SIEM YARA 规则导入 每日
VT / MISP 上传规则共享 每周
Python 调用 YARA 的进阶用法
python 复制代码
import yara
import psutil
# 编译规则
rules = yara.compile(filepath='/opt/yara_rules/index.yar')
# 扫描单个文件
matches = rules.match('/tmp/sample.exe', timeout=30)
for m in matches:
    print(f"[!] {m.rule} - meta: {m.meta}")
# 扫描运行中的进程(DFIR 场景)
for proc in psutil.process_iter(['pid', 'name']):
    try:
        matches = rules.match(pid=proc.info['pid'])
        if matches:
            print(f"[!] ALERT: PID {proc.info['pid']} ({proc.info['name']}) "
                  f"matches {[m.rule for m in matches]}")
    except (psutil.AccessDenied, psutil.NoSuchProcess):
        pass

7.4 规则的生命周期管理

规则不是"写完就完"------需要持续维护:

text 复制代码
【规则生命周期】
  出生:通过验证,部署到生产
  ↓
  活跃:命中告警,定期召回测试
  ↓
  老化:连续 90 天无命中,或家族特征已失效
  ↓
  退役:从生产库移除,归档到 rules/retired/
  ↓
  复活:如果该家族再次活跃,从 retired/ 恢复

定期巡检清单

text 复制代码
□ 每周:扫一次好样本库,确认零误报
□ 每月:扫一次恶意样本库,确认召回率
□ 每季度:审计规则 meta 完整性(作者、日期、参考)
□ 每半年:清理 6 个月无命中的规则(移入 retired/)

结语:规则是"分析成果的长期资产",不是"一次性代码"

回顾本篇,YARA 规则编写实战可以浓缩为三条核心原则:

原则一:字符串的"独特性"决定规则的"精度" 。把字符串扔进 Google/VT 搜一搜,搜出 10 个以上良性命中就丢掉------这是最朴素也最有效的"防胡椒"手段。规则的质量,取决于你愿意花多少时间在字符串筛选上

原则二:条件的"平衡"决定规则的"生命力" 。太严会漏,太松会误。filesize + PE 头 + 2-3 条独特字符串 是生产规则的"黄金组合";any of them 只能用于狩猎all of them 容易被绕过 ------2 of ($s*) 这类"部分匹配"是大多数场景的最佳解

原则三:迭代是规则的"宿命"没有一条规则能一次写对 ------写规则、扫好样本、分析误报、修字符串、再扫、再修......直到零误报、召回率达标,才敢说"这是生产规则"。YARA-CI、yaraQA、好样本库是你这条迭代的"护栏",没有它们,你只能靠运气。

最后送给从业者一句话:YARA 规则是恶意软件分析的"最后一公里"------它把你的分析成果从"报告"转化为"资产",从"一次性的洞察"转化为"长期的防御能力" 。当你能在 24 小时内从拿到样本到提交一条零误报、高召回的生产规则,你拥有的就不仅是分析能力,而是整个组织的检测能力

最后一句忠告规则的"个性"就是它的价值 ------每一条独特的 Mutex 名、每一条 PDB 路径、每一条 Malleable Profile 特征,都是你在对抗中"磨"出来的武器。不要把 YARA 规则写成模板化的"通用检测",要把它写成有故事的"威胁叙事"------三个月后读起来,你依然能从每条字符串里看到当时分析样本时的思考。

相关推荐
志栋智能1 小时前
安全超自动化:实现安全策略动态调整的保障
网络·安全·自动化
明月_清风1 小时前
DeepSeek Harness 安全审计实录:四个 PoC 揭露的 Agent 运行时"信任危机"
后端·安全·agent
可视化运维管理爱好者1 小时前
机房工勘记录器分享
运维·网络·nvisual
超级架构师1 小时前
连接企业系统,不等于把接口直接交给 Agent:LIMENORA 的集成边界
网络·人工智能·架构·ai编程
IT19952 小时前
双网卡 Windows 网络混乱?路由配置一步解决内外网冲突
网络
国科安芯2 小时前
星载数据处理单元中单粒子翻转防护机制的设计考量与实现路径
网络·单片机·嵌入式硬件·架构·抗辐射·星载数据处理·单粒子
Lynne3092 小时前
IT/OT融合为什么难?从网络、协议到实时性的技术问题
网络
FfHUCisI2 小时前
Golang 网络轮询器 netpoll:把阻塞 IO 变成事件通知
开发语言·网络·golang
Zhu7583 小时前
部署安全的pg数据库,搭配pgadmin实现web界面管理
前端·数据库·安全