以下是 YARA 的 C 语言完整集成与开发方法,包括:
- YARA C API 的使用
 - 规则编译、文件扫描、回调处理
 - 完整的 C 示例代码
 - 编译与链接方法
 - 高级用法(自定义外部变量、模块支持等)
 
🧰 一、前置条件
1. 安装 YARA 开发库
Ubuntu/Debian
sudo apt-get install libyara-dev yara
CentOS/RHEL
sudo yum install yara-devel
# 或使用 dnf(新版本)
sudo dnf install yara-devel
macOS
brew install yara
确保
yara命令可用,并且头文件(yara.h)和库文件(libyara.so/libyara.a)已安装。
📦 二、YARA C API 核心概念
YARA C API 主要包含以下组件:
| 组件 | 说明 | 
|---|---|
YR_COMPILER | 用于编译 YARA 规则 | 
YR_RULES | 编译后的规则集合 | 
yr_rules_scan_*(...) | 扫描文件/内存/文件描述符 | 
YR_CALLBACK_FUNC | 匹配回调函数(接收匹配结果) | 
🧪 三、完整 C 示例代码:扫描文件并输出匹配结果
文件:yara_scan.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <yara.h>
// 回调函数:处理匹配结果
int callback_function(YR_SCAN_CONTEXT* context, int message, void* message_data, void* user_data)
{
    YR_RULE* rule;
    YR_STRING* string;
    YR_MATCH* match;
    switch (message)
    {
        case CALLBACK_MSG_RULE_MATCHING:
            rule = (YR_RULE*) message_data;
            printf("[+] 匹配规则: %s", rule->identifier);
            if (rule->tags[0] != NULL)
            {
                printf(" (标签: ");
                for (int i = 0; rule->tags[i] != NULL; i++)
                {
                    if (i > 0) printf(", ");
                    printf("%s", rule->tags[i]);
                }
                printf(")");
            }
            printf("\n");
            // 打印匹配的字符串
            yr_rule_strings_foreach(rule, string)
            {
                yr_string_matches_foreach(context, string, match)
                {
                    printf("    ├─ 字符串: %s = \"%.*s\" @ 0x%llx\n",
                           string->identifier,
                           match->data_length,
                           match->data,
                           match->base + match->offset);
                }
            }
            break;
        case CALLBACK_MSG_RULE_NOT_MATCHING:
            // 可选:打印未匹配的规则
            // rule = (YR_RULE*) message_data;
            // printf("[-] 未匹配: %s\n", rule->identifier);
            break;
        case CALLBACK_MSG_SCAN_FINISHED:
            // 扫描完成
            break;
        default:
            break;
    }
    return CALLBACK_CONTINUE;  // 继续扫描
}
int main(int argc, char** argv)
{
    if (argc != 3)
    {
        fprintf(stderr, "用法: %s <规则文件.yar> <目标文件>\n", argv[0]);
        return 1;
    }
    const char* rules_file = argv[1];
    const char* target_file = argv[2];
    YR_COMPILER* compiler = NULL;
    YR_RULES* rules = NULL;
    FILE* rule_fh = NULL;
    int result;
    // 初始化 YARA
    yr_initialize();
    // 创建编译器
    result = yr_compiler_create(&compiler);
    if (result != ERROR_SUCCESS)
    {
        fprintf(stderr, "无法创建编译器: %d\n", result);
        goto cleanup;
    }
    // 打开规则文件
    rule_fh = fopen(rules_file, "r");
    if (!rule_fh)
    {
        perror("无法打开规则文件");
        result = -1;
        goto cleanup;
    }
    // 编译规则(从文件)
    yr_compiler_add_file(compiler, rule_fh, NULL, rules_file);
    // 检查编译错误
    if (compiler->errors > 0)
    {
        fprintf(stderr, "规则编译失败!\n");
        goto cleanup;
    }
    // 获取编译后的规则
    result = yr_compiler_get_rules(compiler, &rules);
    if (result != ERROR_SUCCESS)
    {
        fprintf(stderr, "无法获取规则: %d\n", result);
        goto cleanup;
    }
    // 扫描目标文件
    printf("🔍 开始扫描文件: %s\n", target_file);
    result = yr_rules_scan_file(rules, target_file, 0, callback_function, NULL, 0);
    if (result != ERROR_SUCCESS)
    {
        fprintf(stderr, "扫描失败: %d\n", result);
    }
cleanup:
    // 清理资源
    if (rule_fh) fclose(rule_fh);
    if (rules) yr_rules_destroy(rules);
    if (compiler) yr_compiler_destroy(compiler);
    yr_finalize();
    return result == ERROR_SUCCESS ? 0 : 1;
}
🔧 四、编写测试 YARA 规则文件
文件:test.yar
rule HelloWorldRule
{
    tags: test demo
    strings:
        $greeting = "Hello, World!" ascii
        $number = { 48 65 6C 6C 6F }  // "Hello" in hex
    condition:
        all of them
}
🛠️ 五、编译 C 程序
方法 1:使用 gcc 直接编译
gcc -o yara_scan yara_scan.c -lyara
如果提示找不到
-lyara,请确认libyara.so在/usr/lib或/usr/local/lib。
方法 2:指定路径(如自定义安装)
gcc -o yara_scan yara_scan.c \
    -I/usr/local/include \
    -L/usr/local/lib \
    -lyara
▶️ 六、运行测试
# 创建测试文件
echo "Hello, World!" > test.txt
# 编译并运行
gcc -o yara_scan yara_scan.c -lyara
./yara_scan test.yar test.txt
预期输出:
🔍 开始扫描文件: test.txt
[+] 匹配规则: HelloWorldRule (标签: test, demo)
    ├─ 字符串: $greeting = "Hello, World!" @ 0x0
    ├─ 字符串: $number = "Hello" @ 0x0
⚙️ 七、高级功能集成
1. 使用外部变量(External Variables)
修改规则:
rule HasKeyword
{
    condition:
        contains(text, keyword)
}
在 C 中设置外部变量:
YR_EXTERNAL_VARIABLE ext_vars[] = {
    { .identifier = "keyword", .type = YE_STRING, .value = {.ss = "malware"} },
    { .identifier = "text",    .type = YE_STRING, .value = {.ss = "this is a malware sample"} },
    { .identifier = NULL }  // 结束标记
};
// 扫描时传入
yr_rules_scan_mem(..., callback, NULL, 0, ext_vars);
2. 扫描内存缓冲区
char buffer[] = "Hello, World!";
size_t buffer_len = strlen(buffer);
yr_rules_scan_mem(rules, buffer, buffer_len, 0, callback_function, NULL, 0);
3. 启用内置模块(如 hash, pe, elf)
// 启用 PE 模块
yr_rules_load(rules, "compiled_rules.bin");  // 可选:保存编译后的规则
yr_initialize();
// 启用模块(必须在扫描前)
yr_enable_features(YARA_FEATURE_EXTERNAL_VARIABLES | YARA_FEATURE_MODULES);
// 或使用宏控制
#define YR_ENABLE_CRYPTO
注意:使用
pe,hash等模块需在编译 YARA 时启用对应功能。
📁 八、保存/加载编译后的规则(提高性能)
// 保存编译后的规则到文件
yr_rules_save(rules, "compiled.yarc");
// 加载已编译规则
YR_RULES* loaded_rules;
yr_rules_load("compiled.yarc", &loaded_rules);
// 直接扫描
yr_rules_scan_file(loaded_rules, target_file, 0, callback, NULL, 0);
// 销毁
yr_rules_destroy(loaded_rules);
适用于规则不变、频繁扫描的场景(如安全网关、EDR)。
🧩 九、常见错误与解决
| 错误 | 原因 | 解决 | 
|---|---|---|
undefined reference to 'yr_initialize' | 未链接 -lyara | 添加 -lyara | 
cannot open shared object libyara.so | 动态库未找到 | sudo ldconfig 或设置 LD_LIBRARY_PATH | 
| 编译规则失败 | 语法错误 | 使用 yara test.yar /bin/ls 测试规则 | 
| 内存扫描崩溃 | 缓冲区为空或未初始化 | 检查指针和长度 | 
📚 十、官方文档与资源
- YARA C API 文档:https://yara.readthedocs.io/en/stable/capi.html
 - 头文件参考:
/usr/include/yara.h - 示例代码:https://github.com/VirusTotal/yara/tree/master/tests
 - YARA 构建说明:https://github.com/VirusTotal/yara#building-from-sources
 
✅ 总结
通过 C 语言集成 YARA,你可以:
- 将 YARA 深度嵌入到安全产品中(如杀毒引擎、EDR、防火墙)
 - 实现高性能、低延迟的实时扫描
 - 与自定义解析器、沙箱、驱动联动
 - 支持跨平台(Linux、Windows、macOS)