YARA 的 C 语言完整集成与开发方法

以下是 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. 启用内置模块(如 hashpeelf

// 启用 PE 模块
yr_rules_load(rules, "compiled_rules.bin");  // 可选:保存编译后的规则
yr_initialize();

// 启用模块(必须在扫描前)
yr_enable_features(YARA_FEATURE_EXTERNAL_VARIABLES | YARA_FEATURE_MODULES);

// 或使用宏控制
#define YR_ENABLE_CRYPTO

注意:使用 pehash 等模块需在编译 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)
此条目发表在未分类分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注