1. 什么是 Yara 引擎?
Yara 是一个开源的恶意代码查杀引擎,用来识别和分类恶意软件样本。Yara 本身不提供杀毒功能,也没有自己的特征库,所以它只是个引擎而已。
Yara 引擎需要特征规则库的支持。特征规则是由一系列字符串和一个布尔型表达式构成的描述来阐述其逻辑,支持与或非等多种条件,以此来识别和分类恶意软件或者程序。
Yara 引擎是跨平台的,可在 Windows、Linux 和 Mac OS X 上运行。
2. Yara 引擎安装
这里我们在 CentOS7.2 上用 yara-3.7.0.tar.gz 做演示。
安装前,请先确保必要的安装包已经安装:
yum install automake libtool make gcc
下面我们用源码安装 Yara 引擎:
tar -zxf yara-3.7.0.tar.gz
cd yara-3.7.0
./bootstrap.sh
./configure
make
make install
安装完后,可以用 make check 检查是否正常安装:
============================================================================
Testsuite summary for yara 3.7.0
============================================================================
# TOTAL: 7
# PASS: 7
# SKIP: 0
# XFAIL: 0
# FAIL: 0
# XPASS: 0
# ERROR: 0
============================================================================
3. Yara 命令扫描二进制文件
我们知道,Yara 引擎仅仅是一个提供扫描功能的可执行程序,它的主要特点是灵活的特征规则。这里我们不会长篇介绍如何去写规则,我会用一个最简单的规则演示如何使用 Yara 引擎扫描二进制文件
/usr/bin/netstat
。
在命令行下执行如下语句:
echo "rule dummy { condition: true }" > my_first_rule
双引号中间的内容就是规则内容,规则名是 dummy,条件是 true,表示扫描任何文件都会命中此规则。
下面我们就用这个规则去扫描二进制文件
/usr/bin/netstat
。
$ yara my_first_rule /usr/bin/netstat
dummy /usr/bin/netstat
Yara 的第一个参数是规则文件 my_first_rule,第二个参数是要扫描的二进制文件名。可以看到输出结果显示
/usr/bin/netstat
命中了规则 dummy。
Yara 命令的详细使用方法请参考 yara –help,这里不再赘述。
4. Yara API 扫描二进制文件剖析
Yara 引擎不仅可以扫描文件,还可以扫描内存、进程等。对文件的扫描,是把文件先内存映射当前应用程序的地址空间。对进程的扫描,是先把进程通过 PTRACE_ATTACH 挂起后,获取进程内存,扫描结束后 PTRACE_DETACH 分离。总而言之,不管哪种方式的扫描,Yara 引擎扫描的本质都是对内存的扫描。
这里我们以 Yara 的 C API 为例,详细介绍如何扫描二进制文件。
4.1 Yara 初始化
初始化由 yr_initialize() 完成,用来分配 libyara 所需要的资源和初始化内部数据结构。扫描结束时,记得要调用 yr_finalize() 函数释放相关的资源。
多线程中只需要在主线程中调用一次 yr_initialize() 和 yr_finalize()。相关线程结束时,需要调用 yr_finalize_thread() 来释放资源。
4.2 特征规则编译
在使用特征规则扫描文件前,需要先创建规则编译器来编译这些规则。编译器创建由 yr_compiler_create() 函数完成,创建完成后,会得到一个 YR_COMPILER* 类型的编译器指针。
扫描结束后需要调用 yr_compiler_destroy() 函数释放 YR_COMPILER* 指向的资源。
规则编译器创建后,需要添加特征规则。Yara 提供了多种添加方式。可以把多个规则写到文件中,由 yr_compiler_add_file() 函数或 yr_compiler_add_fd() 加载特征库文件。也可以使用 yr_compiler_add_string() 函数加载一条特征规则。
如果特征库文件中的某个规则格式错误,加载函数不会停止加载,而是将正确的特征规则加载,将错误的特征规则数目返回。如果特征库文件完全没有问题,那么函数返回值为 0.
4.3 获取编译后的特征规则
在成功加载了特征库文件以后,可以调用 yr_compiler_get_rules() 函数得到编译后的特征规则。该函数将返回一个 YR_RULES* 的指针。在下面提到的扫描函数中,这个指针将要被用到。
YR_RULES* 使用完之后,需要调用 yr_rules_destroy() 函数释放资源。
4.4 扫描二进制文件
获取特征规则 YR_RULES* 指针后,可以调用 yr_rules_scan_file() 函数来扫描文件。
函数原型如下:
int yr_rules_scan_file(YR_RULES* rules,
const char* filename,
int flags,
YR_CALLBACK_FUNC callback,
void* user_data,
int timeout);
其中,前两个参数一目了然,rules 为编译后的特征规则,filename 是要扫描的二进制文件。Flags 指定为唯一的标记 SCAN_FLAGS_FAST_MODE 即可,表示文件内容当有多处匹配规则时,只需要匹配一次即可。Timeout 是设定超时时间,0 表示永不超时,直到扫描完成。
Yara 引擎会轮询匹配每一个特征规则,每次匹配都会调用回调函数 callback,user_data 是 callback 的参数。
YR_CALLBACK_FUNC 回调函数的原型如下:
int callback_function(
int message,
void* message_data,
void* user_data);
其中,message 的常用值可能是:
CALLBACK_MSG_RULE_MATCHING
CALLBACK_MSG_RULE_NOT_MATCHING
CALLBACK_MSG_SCAN_FINISHED
当 message 为 CALLBACK_MSG_RULE_MATCHING 或 CALLBACK_MSG_RULE_NOT_MATCHING 时,表示是否已匹配某一规则。此时 message_data 指向匹配的规则 YR_RULE*,可以通过 YR_RULE 结构中的 identifier 获取此时正在进行匹配的规则名称。
当 message 为 CALLBACK_MSG_SCAN_FINISHED 时,表示扫描已完成,此时,message_data 为 NULL。
Callback 的返回值定义如下:
CALLBACK_CONTINUE
CALLBACK_ABORT
CALLBACK_ERROR
其中,CALLBACK_CONTINUE 表示规则匹配继续进行。
CALLBACK_ABORT 表示中止本次扫描,但此时扫描文件的主函数 yr_rules_scan_file() 会返回 ERROR_SUCCESS。
CALLBACK_ERROR 表示发生了扫描错误,会中止本次扫描,但此时扫描文件的主函数 yr_rules_scan_file() 会返回 ERROR_CALLBACK_ERROR。
至此,二进制文件扫描函数的使用方法已经介绍完毕。
最后,用一个例子来说明如何写扫描文件的回调,user_data 作为 callback 的回调参数,传递扫描的文件名:
int filescan_callback(int message, void *message_data, void *user_data) {
if (message == CALLBACK_MSG_RULE_MATCHING) {
//匹配该特征规则,打印匹配信息后,结束本次扫描。
printf("filename:%s match rulename:%s !!!", (char *)(user_data), ((YR_RULE*) message_data)->identifier);
return CALLBACK_ABORT;
}
if (message == CALLBACK_MSG_SCAN_FINISHED) {
//扫描完成,没有匹配任何特征规则。
printf("filename:%s scan finished !!!", (char *)(user_data));
}
//没有匹配该特征规则,继续匹配下一条特征规则。
return CALLBACK_CONTINUE;
}
本文作者:沙培龙
文章看完啦,不如来官网看看?滴滴云3-5折活动聚惠来袭!
与其看教程,不如实际操作下?