Skip to content

Instantly share code, notes, and snippets.

@dmknght
Last active October 30, 2021 01:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmknght/6342ea7693dc960b7429d85fc5ff879c to your computer and use it in GitHub Desktop.
Save dmknght/6342ea7693dc960b7429d85fc5ff879c to your computer and use it in GitHub Desktop.
Try to make ClamAV engine uses Yara pattern matching engine

C code. Compile gcc <filename>.c -o run -lclamav -lyara Problems:

  1. Scanner sometime doesn't run. Possibly threading problem of scan engine
  2. 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.
  3. 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();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment