C code. Compile gcc <filename>.c -o run -lclamav -lyara
Problems:
- Scanner sometime doesn't run. Possibly threading problem of scan engine
- Zip file interrupts when first file is matched as malware. It is possibly to bypass other files in archive file. We can solve it by change CL_VIRUS to CL_CLEAN in scan callback.
- No method to get file_path (full file path) yet
#include "clamav.h"
#include "yara.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
YR_RULES* rules = NULL;
char *yr_db_path = "/home/dmknght/ParrotProjects/rkcheck/database/signatures.ydb";
typedef struct UserData {
int scan_message;
const char* matched_rule;
} UserData;
int yr_callback_func(YR_SCAN_CONTEXT* context, int message, void* message_data, void* user_data)
{
/*
Cast user_data (*((UserData*) (user_data))).scan_message
*/
struct UserData data = (*((UserData*) (user_data)));
struct YR_RULE* scan_data = ((YR_RULE*) (message_data));
if (message == CALLBACK_MSG_RULE_MATCHING)
{
(*((UserData*) (user_data))).scan_message = CL_VIRUS;
(*((UserData*) (user_data))).matched_rule = scan_data->identifier;
return CALLBACK_ABORT;
}
return ERROR_SUCCESS;
}
static cl_error_t scan_callback(int fd, const char *type, void *context) {
int flags = SCAN_FLAGS_FAST_MODE;
int timeout = 1000000;
UserData user_data;
user_data.scan_message = CL_CLEAN;
yr_rules_scan_fd(rules, fd, flags, yr_callback_func, &user_data, timeout);
if (user_data.scan_message == CL_VIRUS)
{
printf("Detected %s\n", user_data.matched_rule);
return CL_VIRUS;
}
else if (user_data.scan_message == CL_CLEAN)
{
return CL_CLEAN;
}
}
int main() {
static struct cl_engine *engine;
const char *virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
struct cl_scan_options options;
int stack_size = DEFAULT_STACK_SIZE;
int max_strings_per_rule = DEFAULT_MAX_STRINGS_PER_RULE;
cl_init(CL_INIT_DEFAULT);
yr_initialize();
engine = cl_engine_new();
cl_engine_compile(engine);
if (yr_rules_load(yr_db_path, &rules) != ERROR_SUCCESS)
printf("Failed to load yara rules\n");
printf("Loaded %d rules\n", rules->num_rules);
yr_set_configuration(YR_CONFIG_STACK_SIZE, &stack_size);
yr_set_configuration(YR_CONFIG_MAX_STRINGS_PER_RULE, &max_strings_per_rule);
cl_engine_set_clcb_pre_scan(engine, scan_callback);
cl_scanfile("/tmp/hello1.zip", &virname, &scanned, engine, &options);
// cl_scanfile("/tmp/hello", &virname, &scanned, engine, &options);
// cl_scanfile("/tmp/04b5e29283c60fcc255f8d2f289238430a10624e457f12f1bc866454110830a2_detected", &virname, &scanned, engine, &options);
cl_engine_free(engine);
if (rules != NULL)
yr_rules_destroy(rules);
yr_finalize();
}