/** * Compile a single rule file and load it into rule pointer. */ Status compileSingleFile(const std::string& file, YR_RULES** rules) { YR_COMPILER *compiler = nullptr; int result = yr_compiler_create(&compiler); if (result != ERROR_SUCCESS) { VLOG(1) << "Could not create compiler: " + std::to_string(result); return Status(1, "Could not create compiler: " + std::to_string(result)); } yr_compiler_set_callback(compiler, YARACompilerCallback, nullptr); bool compiled = false; YR_RULES *tmp_rules; VLOG(1) << "Loading " << file; // First attempt to load the file, in case it is saved (pre-compiled) // rules. // // If you want to use saved rule files you must have them all in a single // file. This is easy to accomplish with yarac(1). result = yr_rules_load(file.c_str(), &tmp_rules); if (result != ERROR_SUCCESS && result != ERROR_INVALID_FILE) { yr_compiler_destroy(compiler); return Status(1, "Error loading YARA rules: " + std::to_string(result)); } else if (result == ERROR_SUCCESS) { *rules = tmp_rules; } else { compiled = true; // Try to compile the rules. FILE *rule_file = fopen(file.c_str(), "r"); if (rule_file == nullptr) { yr_compiler_destroy(compiler); return Status(1, "Could not open file: " + file); } int errors = yr_compiler_add_file(compiler, rule_file, nullptr, file.c_str()); fclose(rule_file); rule_file = nullptr; if (errors > 0) { yr_compiler_destroy(compiler); // Errors printed via callback. return Status(1, "Compilation errors"); } } if (compiled) { // All the rules for this category have been compiled, save them in the map. result = yr_compiler_get_rules(compiler, *(&rules)); if (result != ERROR_SUCCESS) { yr_compiler_destroy(compiler); return Status(1, "Insufficient memory to get YARA rules"); } } if (compiler != nullptr) { yr_compiler_destroy(compiler); compiler = nullptr; } return Status(0, "OK"); }
int main( int argc, char const* argv[]) { YR_COMPILER* compiler; YR_RULES* rules; FILE* rule_file; EXTERNAL* external; int pid; int i; int errors; int result; THREAD thread[MAX_THREADS]; if (!process_cmd_line(argc, argv)) return 0; if (argc == 1 || optind == argc) { show_help(); return 0; } yr_initialize(); result = yr_rules_load(argv[optind], &rules); if (result == ERROR_UNSUPPORTED_FILE_VERSION || result == ERROR_CORRUPT_FILE) { print_scanning_error(result); return; } if (result == ERROR_SUCCESS) { external = externals_list; while (external != NULL) { switch (external->type) { case EXTERNAL_TYPE_INTEGER: yr_rules_define_integer_variable( rules, external->name, external->integer); break; case EXTERNAL_TYPE_BOOLEAN: yr_rules_define_boolean_variable( rules, external->name, external->boolean); break; case EXTERNAL_TYPE_STRING: yr_rules_define_string_variable( rules, external->name, external->string); break; } external = external->next; } } else { if (yr_compiler_create(&compiler) != ERROR_SUCCESS) return 0; external = externals_list; while (external != NULL) { switch (external->type) { case EXTERNAL_TYPE_INTEGER: yr_compiler_define_integer_variable( compiler, external->name, external->integer); break; case EXTERNAL_TYPE_BOOLEAN: yr_compiler_define_boolean_variable( compiler, external->name, external->boolean); break; case EXTERNAL_TYPE_STRING: yr_compiler_define_string_variable( compiler, external->name, external->string); break; } external = external->next; } compiler->error_report_function = print_compiler_error; rule_file = fopen(argv[optind], "r"); if (rule_file != NULL) { yr_compiler_push_file_name(compiler, argv[optind]); errors = yr_compiler_add_file(compiler, rule_file, NULL); fclose(rule_file); if (errors == 0) yr_compiler_get_rules(compiler, &rules); yr_compiler_destroy(compiler); if (errors > 0) { yr_finalize(); return 0; } } else { fprintf(stderr, "could not open file: %s\n", argv[optind]); return 0; } } mutex_init(&output_mutex); if (is_numeric(argv[argc - 1])) { pid = atoi(argv[argc - 1]); result = yr_rules_scan_proc( rules, pid, callback, (void*) argv[argc - 1], fast_scan, timeout); if (result != ERROR_SUCCESS) print_scanning_error(result); } else if (is_directory(argv[argc - 1])) { file_queue_init(); for (i = 0; i < threads; i++) { if (create_thread(&thread[i], scanning_thread, (void*) rules) != 0) return ERROR_COULD_NOT_CREATE_THREAD; } scan_dir( argv[argc - 1], recursive_search, rules, callback); file_queue_finish(); // Wait for scan threads to finish for (i = 0; i < threads; i++) thread_join(&thread[i]); file_queue_destroy(); } else { result = yr_rules_scan_file( rules, argv[argc - 1], callback, (void*) argv[argc - 1], fast_scan, timeout); if (result != ERROR_SUCCESS) { fprintf(stderr, "Error scanning %s: ", argv[argc - 1]); print_scanning_error(result); } } yr_rules_destroy(rules); yr_finalize(); mutex_destroy(&output_mutex); cleanup(); return 1; }
/** * Given a vector of strings, attempt to compile them and store the result * in the map under the given category. */ Status handleRuleFiles(const std::string& category, const pt::ptree& rule_files, std::map<std::string, YR_RULES*>* rules) { YR_COMPILER *compiler = nullptr; int result = yr_compiler_create(&compiler); if (result != ERROR_SUCCESS) { VLOG(1) << "Could not create compiler: " + std::to_string(result); return Status(1, "Could not create compiler: " + std::to_string(result)); } yr_compiler_set_callback(compiler, YARACompilerCallback, nullptr); bool compiled = false; for (const auto& item : rule_files) { YR_RULES *tmp_rules; const auto rule = item.second.get("", ""); VLOG(1) << "Loading " << rule; std::string full_path; if (rule[0] != '/') { full_path = std::string("/etc/osquery/yara/") + rule; } else { full_path = rule; } // First attempt to load the file, in case it is saved (pre-compiled) // rules. Sadly there is no way to load multiple compiled rules in // succession. This means that: // // saved1, saved2 // results in saved2 being the only file used. // // Also, mixing source and saved rules results in the saved rules being // overridden by the combination of the source rules once compiled, e.g.: // // file1, saved1 // result in file1 being the only file used. // // If you want to use saved rule files you must have them all in a single // file. This is easy to accomplish with yarac(1). result = yr_rules_load(full_path.c_str(), &tmp_rules); if (result != ERROR_SUCCESS && result != ERROR_INVALID_FILE) { yr_compiler_destroy(compiler); return Status(1, "Error loading YARA rules: " + std::to_string(result)); } else if (result == ERROR_SUCCESS) { // If there are already rules there, destroy them and put new ones in. if (rules->count(category) > 0) { yr_rules_destroy((*rules)[category]); } (*rules)[category] = tmp_rules; } else { compiled = true; // Try to compile the rules. FILE *rule_file = fopen(full_path.c_str(), "r"); if (rule_file == nullptr) { yr_compiler_destroy(compiler); return Status(1, "Could not open file: " + full_path); } int errors = yr_compiler_add_file(compiler, rule_file, nullptr, full_path.c_str()); fclose(rule_file); rule_file = nullptr; if (errors > 0) { yr_compiler_destroy(compiler); // Errors printed via callback. return Status(1, "Compilation errors"); } } } if (compiled) { // All the rules for this category have been compiled, save them in the map. result = yr_compiler_get_rules(compiler, &((*rules)[category])); if (result != ERROR_SUCCESS) { yr_compiler_destroy(compiler); return Status(1, "Insufficient memory to get YARA rules"); } } if (compiler != nullptr) { yr_compiler_destroy(compiler); compiler = nullptr; } return Status(0, "OK"); }
bool Yara::load_rules(const std::string& rule_filename) { if (_current_rules == rule_filename) { return true; } else { // The previous rules and compiler have to be freed manually. _clean_compiler_and_rules(); } bool res = false; int retval; // Look for a compiled version of the rule file first. if (boost::filesystem::exists(rule_filename + "c")) { // File extension is .yarac instead of .yara. retval = yr_rules_load((rule_filename + "c").c_str(), &_rules); } else { retval = yr_rules_load(rule_filename.c_str(), &_rules); } // Yara rules compiled with a previous Yara version. Delete and recompile. if (retval == ERROR_UNSUPPORTED_FILE_VERSION) { boost::filesystem::remove(rule_filename + "c"); } if (retval != ERROR_SUCCESS && retval != ERROR_INVALID_FILE && retval != ERROR_UNSUPPORTED_FILE_VERSION) { PRINT_ERROR << "Could not load yara rules (" << translate_error(retval) << ")." << std::endl; return false; } if (retval == ERROR_SUCCESS) { return true; } else if (retval == ERROR_INVALID_FILE || retval == ERROR_UNSUPPORTED_FILE_VERSION) // Uncompiled rules { if (yr_compiler_create(&_compiler) != ERROR_SUCCESS) { return false; } yr_compiler_set_callback(_compiler, compiler_callback, nullptr); FILE* rule_file = fopen(rule_filename.c_str(), "r"); if (rule_file == nullptr) { return false; } retval = yr_compiler_add_file(_compiler, rule_file, nullptr, rule_filename.c_str()); if (retval != 0) { PRINT_ERROR << "Could not compile yara rules (" << retval << " error(s))." << std::endl; goto END; } retval = yr_compiler_get_rules(_compiler, &_rules); if (retval != ERROR_SUCCESS) { goto END; } // Save the compiled rules to improve load times. // /!\ The compiled rules will have to be deleted if the original (readable) rule file is updated! // TODO: Compare timestamps and recompile automatically. retval = yr_rules_save(_rules, (rule_filename + "c").c_str()); if (retval != ERROR_SUCCESS) { goto END; } res = true; _current_rules = rule_filename; END: if (rule_file != nullptr) { fclose(rule_file); } } return res; }