Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,39 @@ if test x"$lightgrep" == x"yes"; then
LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs-only-L --libs-only-other lightgrep`"
fi

################################################################
## yara-x support
##
AC_ARG_ENABLE([yara],
AS_HELP_STRING([--disable-yara], [Disable YARA scanning]),
[],
[AC_DEFINE(USE_YARA, 1, [Use YARA scanning]) yara="yes"])
if test x"$yara" == x"yes"; then
m4_ifndef([PKG_CHECK_MODULES],
[AC_MSG_ERROR([pkg-config autoconf macros are missing; try installing pkgconfig])])

if test x"$mingw" == x"yes" ; then
# get static flags when cross-compiling with mingw
PKG_CONFIG="$PKG_CONFIG --static"
else
# pkg-config doesn't look in /usr/local/lib on some systems
if test x"$PKG_CONFIG_PATH" != x; then
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
else
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
fi
fi

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to consolidate this pkg-config block with the one above it for lightgrep to avoid duplication.


m4_ifdef([PKG_CHECK_MODULES],
[PKG_CHECK_MODULES([yara], [yara_x_capi])])

AC_DEFINE([HAVE_YARAX], 1, [Define to 1 if you have libyara_x_capi.])

CPPFLAGS="$CPPFLAGS $yara_CFLAGS"
LIBS="$LIBS `$PKG_CONFIG --libs-only-l yara_x_capi`"
LDFLAGS="$LDFLAGS `$PKG_CONFIG --libs-only-L --libs-only-other yara_x_capi`"
fi

################################################################
## LIBEWF support

Expand Down
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ scanners_builtin = \
scan_winprefetch.cpp \
scan_wordlist.cpp scan_wordlist.h \
scan_xor.cpp \
scan_yarax.cpp \
scan_zip.cpp \
pcap_writer.cpp \
pcap_writer.h
Expand Down
3 changes: 3 additions & 0 deletions src/bulk_extractor_scanners.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ SCANNER(winpe)
SCANNER(winprefetch)
SCANNER(wordlist)
SCANNER(xor)
#ifdef HAVE_YARAX
SCANNER(yarax)
#endif
SCANNER(zip)


Expand Down
111 changes: 111 additions & 0 deletions src/scan_yarax.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* Plugin: scan_yarax
* Purpose: Run yara-x rules against raw pages
* Reference: https://virustotal.github.io/yara-x/
**/

#include <iostream>

#include "config.h"
#include "be20_api/scanner_params.h"

#ifdef HAVE_YARAX
extern "C" {
#include <yara_x.h>

void scan_yarax(scanner_params &sp);
}

auto YARA_RULE = R"(
rule test_rule {
strings:
$a = "test"
condition:
$a
}
)";

using rules_ptr = std::unique_ptr<YRX_RULES, decltype(&yrx_rules_destroy)>;

rules_ptr& getYaraRules() {
static rules_ptr rules(nullptr, yrx_rules_destroy);
return rules;
}

struct YaraCallbackData {
feature_recorder &Recorder;
pos0_t Pos;
};

void yara_callback(const YRX_RULE* rule, void* userData) {
const uint8_t* ruleID = nullptr;
size_t idLen = 0;
if (yrx_rule_identifier(rule, &ruleID, &idLen) != SUCCESS) {
std::cerr << "Failed to get rule ID in yara_callback" << std::endl;
return;
}
std::string_view ruleIDView(reinterpret_cast<const char*>(ruleID), idLen);
const YaraCallbackData* data = static_cast<YaraCallbackData*>(userData);
data->Recorder.write(data->Pos, std::string(ruleIDView), "");
}

void scan_yarax(scanner_params &sp) {
sp.check_version();
if (sp.phase == scanner_params::PHASE_INIT){
sp.info->set_name("yarax");
sp.info->author = "Jon Stewart";
sp.info->description = "Scans for yara-x rule matches in raw pages";
sp.info->scanner_version = "1.0";
sp.info->feature_defs.push_back(feature_recorder_def("yara-x"));
return;
}
else if (sp.phase == scanner_params::PHASE_INIT2) {
YRX_RULES* rules = nullptr;
YRX_RESULT result = yrx_compile(YARA_RULE, &rules);
if (result != SUCCESS) {
std::cerr << "Failed to compile yara-x rule: " << yrx_last_error() << std::endl;
return;
}
else {
getYaraRules().reset(rules);
}
}
else if (sp.phase == scanner_params::PHASE_SCAN) {
rules_ptr& rules = getYaraRules();
if (!rules) {
return;
}
YRX_SCANNER* scannerRawPtr = nullptr;
YRX_RESULT result = yrx_scanner_create(rules.get(), &scannerRawPtr);
if (result != SUCCESS) {
std::cerr << "Failed to create yara-x scanner: " << yrx_last_error() << std::endl;
return;
}
std::unique_ptr<YRX_SCANNER, decltype(&yrx_scanner_destroy)> scanner(scannerRawPtr, yrx_scanner_destroy);

YaraCallbackData callbackData{sp.named_feature_recorder("yara-x"), sp.sbuf->pos0};

result = yrx_scanner_on_matching_rule(scanner.get(), yara_callback, &callbackData);
if (result != SUCCESS) {
std::cerr << "Failed to set yara-x callback: " << yrx_last_error() << std::endl;
return;
}

// Iterate the sbuf 4KB at a time and scan these pages individually
const sbuf_t *sbuf = sp.sbuf;
const size_t blockSize = 4096;
const uint8_t* curBlock = sbuf->get_buf();
const uint8_t* end = curBlock + sbuf->pagesize;
while (curBlock < end) {
const size_t len = std::min(blockSize, static_cast<size_t>(end - curBlock));
result = yrx_scanner_scan(scanner.get(), curBlock, len);
if (result != SUCCESS) {
std::cerr << "Failed to scan yara-x: " << yrx_last_error() << std::endl;
return;
}
curBlock += len;
}
}
}
#endif