以下是 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)