void yr_compiler_destroy( YR_COMPILER* compiler) { int i; if (compiler->compiled_rules_arena != NULL) yr_arena_destroy(compiler->compiled_rules_arena); if (compiler->sz_arena != NULL) yr_arena_destroy(compiler->sz_arena); if (compiler->rules_arena != NULL) yr_arena_destroy(compiler->rules_arena); if (compiler->strings_arena != NULL) yr_arena_destroy(compiler->strings_arena); if (compiler->code_arena != NULL) yr_arena_destroy(compiler->code_arena); if (compiler->re_code_arena != NULL) yr_arena_destroy(compiler->re_code_arena); if (compiler->automaton_arena != NULL) yr_arena_destroy(compiler->automaton_arena); if (compiler->externals_arena != NULL) yr_arena_destroy(compiler->externals_arena); if (compiler->namespaces_arena != NULL) yr_arena_destroy(compiler->namespaces_arena); if (compiler->metas_arena != NULL) yr_arena_destroy(compiler->metas_arena); yr_hash_table_destroy( compiler->rules_table, NULL); yr_hash_table_destroy( compiler->objects_table, (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy); for (i = 0; i < compiler->file_name_stack_ptr; i++) yr_free(compiler->file_name_stack[i]); yr_free(compiler); }
int yr_rules_destroy( YR_RULES* rules) { YR_EXTERNAL_VARIABLE* external; external = rules->externals_list_head; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { if (external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) yr_free(external->string); external++; } #if WIN32 CloseHandle(rules->mutex); #else pthread_mutex_destroy(&rules->mutex); #endif yr_arena_destroy(rules->arena); yr_free(rules); return ERROR_SUCCESS; }
void yr_re_destroy( RE* re) { if (re->root_node != NULL) yr_re_node_destroy(re->root_node); if (re->code_arena != NULL) yr_arena_destroy(re->code_arena); yr_free(re); }
YR_API int yr_compiler_get_rules( YR_COMPILER* compiler, YR_RULES** rules) { YR_RULES* yara_rules; YARA_RULES_FILE_HEADER* rules_file_header; *rules = NULL; if (compiler->compiled_rules_arena == NULL) FAIL_ON_ERROR(_yr_compiler_compile_rules(compiler)); yara_rules = (YR_RULES*) yr_malloc(sizeof(YR_RULES)); if (yara_rules == NULL) return ERROR_INSUFICIENT_MEMORY; FAIL_ON_ERROR_WITH_CLEANUP( yr_arena_duplicate(compiler->compiled_rules_arena, &yara_rules->arena), yr_free(yara_rules)); rules_file_header = (YARA_RULES_FILE_HEADER*) yr_arena_base_address( yara_rules->arena); yara_rules->externals_list_head = rules_file_header->externals_list_head; yara_rules->rules_list_head = rules_file_header->rules_list_head; yara_rules->match_table = rules_file_header->match_table; yara_rules->transition_table = rules_file_header->transition_table; yara_rules->code_start = rules_file_header->code_start; yara_rules->tidx_mask = 0; FAIL_ON_ERROR_WITH_CLEANUP( yr_mutex_create(&yara_rules->mutex), // cleanup yr_arena_destroy(yara_rules->arena); yr_free(yara_rules)); *rules = yara_rules; return ERROR_SUCCESS; }
int _yr_compiler_compile_rules( YR_COMPILER* compiler) { YARA_RULES_FILE_HEADER* rules_file_header = NULL; YR_ARENA* arena = NULL; YR_RULE null_rule; YR_EXTERNAL_VARIABLE null_external; YR_AC_TABLES tables; int8_t halt = OP_HALT; int result; // Write halt instruction at the end of code. yr_arena_write_data( compiler->code_arena, &halt, sizeof(int8_t), NULL); // Write a null rule indicating the end. memset(&null_rule, 0xFA, sizeof(YR_RULE)); null_rule.g_flags = RULE_GFLAGS_NULL; yr_arena_write_data( compiler->rules_arena, &null_rule, sizeof(YR_RULE), NULL); // Write a null external the end. memset(&null_external, 0xFA, sizeof(YR_EXTERNAL_VARIABLE)); null_external.type = EXTERNAL_VARIABLE_TYPE_NULL; yr_arena_write_data( compiler->externals_arena, &null_external, sizeof(YR_EXTERNAL_VARIABLE), NULL); // Write Aho-Corasick automaton to arena. result = yr_ac_compile( compiler->automaton, compiler->automaton_arena, &tables); if (result == ERROR_SUCCESS) result = yr_arena_create(1024, 0, &arena); if (result == ERROR_SUCCESS) result = yr_arena_allocate_struct( arena, sizeof(YARA_RULES_FILE_HEADER), (void**) &rules_file_header, offsetof(YARA_RULES_FILE_HEADER, rules_list_head), offsetof(YARA_RULES_FILE_HEADER, externals_list_head), offsetof(YARA_RULES_FILE_HEADER, code_start), offsetof(YARA_RULES_FILE_HEADER, match_table), offsetof(YARA_RULES_FILE_HEADER, transition_table), EOL); if (result == ERROR_SUCCESS) { rules_file_header->rules_list_head = (YR_RULE*) yr_arena_base_address( compiler->rules_arena); rules_file_header->externals_list_head = (YR_EXTERNAL_VARIABLE*) yr_arena_base_address(compiler->externals_arena); rules_file_header->code_start = (uint8_t*) yr_arena_base_address( compiler->code_arena); rules_file_header->match_table = tables.matches; rules_file_header->transition_table = tables.transitions; } if (result == ERROR_SUCCESS) { result = yr_arena_append( arena, compiler->code_arena); } if (result == ERROR_SUCCESS) { compiler->code_arena = NULL; result = yr_arena_append( arena, compiler->re_code_arena); } if (result == ERROR_SUCCESS) { compiler->re_code_arena = NULL; result = yr_arena_append( arena, compiler->rules_arena); } if (result == ERROR_SUCCESS) { compiler->rules_arena = NULL; result = yr_arena_append( arena, compiler->strings_arena); } if (result == ERROR_SUCCESS) { compiler->strings_arena = NULL; result = yr_arena_append( arena, compiler->externals_arena); } if (result == ERROR_SUCCESS) { compiler->externals_arena = NULL; result = yr_arena_append( arena, compiler->namespaces_arena); } if (result == ERROR_SUCCESS) { compiler->namespaces_arena = NULL; result = yr_arena_append( arena, compiler->metas_arena); } if (result == ERROR_SUCCESS) { compiler->metas_arena = NULL; result = yr_arena_append( arena, compiler->sz_arena); } if (result == ERROR_SUCCESS) { compiler->sz_arena = NULL; result = yr_arena_append( arena, compiler->automaton_arena); } if (result == ERROR_SUCCESS) { compiler->automaton_arena = NULL; result = yr_arena_append( arena, compiler->matches_arena); } if (result == ERROR_SUCCESS) { compiler->matches_arena = NULL; compiler->compiled_rules_arena = arena; result = yr_arena_coalesce(arena); } else { yr_arena_destroy(arena); } return result; }
YR_API void yr_compiler_destroy( YR_COMPILER* compiler) { YR_FIXUP* fixup; int i; yr_arena_destroy(compiler->compiled_rules_arena); yr_arena_destroy(compiler->sz_arena); yr_arena_destroy(compiler->rules_arena); yr_arena_destroy(compiler->strings_arena); yr_arena_destroy(compiler->code_arena); yr_arena_destroy(compiler->re_code_arena); yr_arena_destroy(compiler->externals_arena); yr_arena_destroy(compiler->namespaces_arena); yr_arena_destroy(compiler->metas_arena); yr_arena_destroy(compiler->automaton_arena); yr_arena_destroy(compiler->matches_arena); yr_ac_automaton_destroy(compiler->automaton); yr_hash_table_destroy( compiler->rules_table, NULL); yr_hash_table_destroy( compiler->strings_table, NULL); yr_hash_table_destroy( compiler->objects_table, (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy); for (i = 0; i < compiler->file_name_stack_ptr; i++) yr_free(compiler->file_name_stack[i]); fixup = compiler->fixup_stack_head; while (fixup != NULL) { YR_FIXUP* next_fixup = fixup->next; yr_free(fixup); fixup = next_fixup; } yr_free(compiler); }
int yr_arena_load_stream( YR_STREAM* stream, YR_ARENA** arena) { YR_ARENA_PAGE* page; YR_ARENA* new_arena; ARENA_FILE_HEADER header; uint32_t reloc_offset; uint8_t** reloc_address; uint8_t* reloc_target; int result; if (yr_stream_read(&header, sizeof(header), 1, stream) != 1) return ERROR_INVALID_FILE; if (header.magic[0] != 'Y' || header.magic[1] != 'A' || header.magic[2] != 'R' || header.magic[3] != 'A') { return ERROR_INVALID_FILE; } if (header.size < 2048) // compiled rules are always larger than 2KB return ERROR_CORRUPT_FILE; if (header.version != ARENA_FILE_VERSION) return ERROR_UNSUPPORTED_FILE_VERSION; result = yr_arena_create(header.size, 0, &new_arena); if (result != ERROR_SUCCESS) return result; page = new_arena->current_page; if (yr_stream_read(page->address, header.size, 1, stream) != 1) { yr_arena_destroy(new_arena); return ERROR_CORRUPT_FILE; } page->used = header.size; if (yr_stream_read(&reloc_offset, sizeof(reloc_offset), 1, stream) != 1) { yr_arena_destroy(new_arena); return ERROR_CORRUPT_FILE; } while (reloc_offset != 0xFFFFFFFF) { if (reloc_offset > header.size - sizeof(uint8_t*)) { yr_arena_destroy(new_arena); return ERROR_CORRUPT_FILE; } yr_arena_make_relocatable(new_arena, page->address, reloc_offset, EOL); reloc_address = (uint8_t**) (page->address + reloc_offset); reloc_target = *reloc_address; if (reloc_target != (uint8_t*) (size_t) 0xFFFABADA) *reloc_address += (size_t) page->address; else *reloc_address = 0; if (yr_stream_read(&reloc_offset, sizeof(reloc_offset), 1, stream) != 1) { yr_arena_destroy(new_arena); return ERROR_CORRUPT_FILE; } } *arena = new_arena; return ERROR_SUCCESS; }
int yr_arena_duplicate( YR_ARENA* arena, YR_ARENA** duplicated) { YR_RELOC* reloc; YR_RELOC* new_reloc; YR_ARENA_PAGE* page; YR_ARENA_PAGE* new_page; YR_ARENA* new_arena; uint8_t** reloc_address; uint8_t* reloc_target; // Only coalesced arenas can be duplicated. assert(arena->flags & ARENA_FLAGS_COALESCED); page = arena->page_list_head; FAIL_ON_ERROR(yr_arena_create(page->size, arena->flags, &new_arena)); new_page = new_arena->current_page; new_page->used = page->used; memcpy(new_page->address, page->address, page->size); reloc = page->reloc_list_head; while (reloc != NULL) { new_reloc = (YR_RELOC*) yr_malloc(sizeof(YR_RELOC)); if (new_reloc == NULL) { yr_arena_destroy(new_arena); return ERROR_INSUFFICIENT_MEMORY; } new_reloc->offset = reloc->offset; new_reloc->next = NULL; if (new_page->reloc_list_head == NULL) new_page->reloc_list_head = new_reloc; if (new_page->reloc_list_tail != NULL) new_page->reloc_list_tail->next = new_reloc; new_page->reloc_list_tail = new_reloc; reloc_address = (uint8_t**) (new_page->address + new_reloc->offset); reloc_target = *reloc_address; if (reloc_target != NULL) { assert(reloc_target >= page->address); assert(reloc_target < page->address + page->used); *reloc_address = reloc_target - \ page->address + \ new_page->address; } reloc = reloc->next; } *duplicated = new_arena; return ERROR_SUCCESS; }
int yr_arena_load( const char* filename, YR_ARENA** arena) { FILE* fh; YR_ARENA_PAGE* page; YR_ARENA* new_arena; ARENA_FILE_HEADER header; int32_t reloc_offset; uint8_t** reloc_address; uint8_t* reloc_target; long file_size; int result; fh = fopen(filename, "rb"); if (fh == NULL) return ERROR_COULD_NOT_OPEN_FILE; fseek(fh, 0, SEEK_END); file_size = ftell(fh); fseek(fh, 0, SEEK_SET); if (fread(&header, sizeof(header), 1, fh) != 1) { fclose(fh); return ERROR_INVALID_FILE; } if (header.magic[0] != 'Y' || header.magic[1] != 'A' || header.magic[2] != 'R' || header.magic[3] != 'A') { fclose(fh); return ERROR_INVALID_FILE; } if (header.size >= (uint32_t)file_size) { fclose(fh); return ERROR_CORRUPT_FILE; } if (header.version > ARENA_FILE_VERSION) { fclose(fh); return ERROR_UNSUPPORTED_FILE_VERSION; } result = yr_arena_create(header.size, 0, &new_arena); if (result != ERROR_SUCCESS) { fclose(fh); return result; } page = new_arena->current_page; if (fread(page->address, header.size, 1, fh) != 1) { fclose(fh); yr_arena_destroy(new_arena); return ERROR_CORRUPT_FILE; } page->used = header.size; if (fread(&reloc_offset, sizeof(reloc_offset), 1, fh) != 1) { fclose(fh); yr_arena_destroy(new_arena); return ERROR_CORRUPT_FILE; } while (reloc_offset != -1) { yr_arena_make_relocatable(new_arena, page->address, reloc_offset, EOL); reloc_address = (uint8_t**) (page->address + reloc_offset); reloc_target = *reloc_address; if (reloc_target != (uint8_t*) (size_t) 0xFFFABADA) *reloc_address += (size_t) page->address; else *reloc_address = 0; if (fread(&reloc_offset, sizeof(reloc_offset), 1, fh) != 1) { fclose(fh); yr_arena_destroy(new_arena); return ERROR_CORRUPT_FILE; } } fclose(fh); *arena = new_arena; return ERROR_SUCCESS; }
int yr_rules_scan_mem_blocks( YR_RULES* rules, YR_MEMORY_BLOCK* block, int scanning_process_memory, YR_CALLBACK_FUNC callback, void* user_data, int fast_scan_mode, int timeout) { YR_RULE* rule; EVALUATION_CONTEXT context; YR_ARENA* matches_arena = NULL; time_t start_time; tidx_mask_t bit; int message; int tidx = 0; int result = ERROR_SUCCESS; if (block == NULL) return ERROR_SUCCESS; context.file_size = block->size; context.mem_block = block; context.entry_point = UNDEFINED; _yr_rules_lock(rules); bit = 1; while (rules->tidx_mask & bit) { tidx++; bit <<= 1; } if (tidx < MAX_THREADS) rules->tidx_mask |= bit; else result = ERROR_TOO_MANY_SCAN_THREADS; _yr_rules_unlock(rules); if (result != ERROR_SUCCESS) return result; yr_set_tidx(tidx); result = yr_arena_create(1024, 0, &matches_arena); if (result != ERROR_SUCCESS) goto _exit; start_time = time(NULL); while (block != NULL) { if (context.entry_point == UNDEFINED) { if (scanning_process_memory) context.entry_point = yr_get_entry_point_address( block->data, block->size, block->base); else context.entry_point = yr_get_entry_point_offset( block->data, block->size); } result = yr_rules_scan_mem_block( rules, block->data, block->size, fast_scan_mode, timeout, start_time, matches_arena); if (result != ERROR_SUCCESS) goto _exit; block = block->next; } result = yr_execute_code( rules, &context, timeout, start_time); if (result != ERROR_SUCCESS) goto _exit; rule = rules->rules_list_head; while (!RULE_IS_NULL(rule)) { if (RULE_IS_GLOBAL(rule) && !(rule->t_flags[tidx] & RULE_TFLAGS_MATCH)) { rule->ns->t_flags[tidx] |= NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL; } rule++; } rule = rules->rules_list_head; while (!RULE_IS_NULL(rule)) { if (rule->t_flags[tidx] & RULE_TFLAGS_MATCH && !(rule->ns->t_flags[tidx] & NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL)) { message = CALLBACK_MSG_RULE_MATCHING; } else { message = CALLBACK_MSG_RULE_NOT_MATCHING; } if (!RULE_IS_PRIVATE(rule)) { switch (callback(message, rule, user_data)) { case CALLBACK_ABORT: result = ERROR_SUCCESS; goto _exit; case CALLBACK_ERROR: result = ERROR_CALLBACK_ERROR; goto _exit; } } rule++; } callback(CALLBACK_MSG_SCAN_FINISHED, NULL, user_data); _exit: _yr_rules_clean_matches(rules); if (matches_arena != NULL) yr_arena_destroy(matches_arena); _yr_rules_lock(rules); rules->tidx_mask &= ~(1 << tidx); _yr_rules_unlock(rules); yr_set_tidx(-1); return result; }
int yr_rules_scan_mem_blocks( YR_RULES* rules, YR_MEMORY_BLOCK* block, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) { YR_SCAN_CONTEXT context; YR_RULE* rule; YR_OBJECT* object; YR_EXTERNAL_VARIABLE* external; YR_ARENA* matches_arena = NULL; time_t start_time; tidx_mask_t bit; int message; int tidx = 0; int result = ERROR_SUCCESS; if (block == NULL) return ERROR_SUCCESS; context.flags = flags; context.callback = callback; context.user_data = user_data; context.file_size = block->size; context.mem_block = block; context.entry_point = UNDEFINED; context.objects_table = NULL; _yr_rules_lock(rules); bit = 1; while (rules->tidx_mask & bit) { tidx++; bit <<= 1; } if (tidx < MAX_THREADS) rules->tidx_mask |= bit; else result = ERROR_TOO_MANY_SCAN_THREADS; _yr_rules_unlock(rules); if (result != ERROR_SUCCESS) return result; yr_set_tidx(tidx); result = yr_arena_create(1024, 0, &matches_arena); if (result != ERROR_SUCCESS) goto _exit; result = yr_hash_table_create(64, &context.objects_table); if (result != ERROR_SUCCESS) goto _exit; external = rules->externals_list_head; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { result = yr_object_from_external_variable( external, &object); if (result == ERROR_SUCCESS) result = yr_hash_table_add( context.objects_table, external->identifier, NULL, (void*) object); if (result != ERROR_SUCCESS) goto _exit; external++; } start_time = time(NULL); while (block != NULL) { if (context.entry_point == UNDEFINED) { if (flags & SCAN_FLAGS_PROCESS_MEMORY) context.entry_point = yr_get_entry_point_address( block->data, block->size, block->base); else context.entry_point = yr_get_entry_point_offset( block->data, block->size); } result = yr_rules_scan_mem_block( rules, block, flags, timeout, start_time, matches_arena); if (result != ERROR_SUCCESS) goto _exit; block = block->next; } result = yr_execute_code( rules, &context, timeout, start_time); if (result != ERROR_SUCCESS) goto _exit; rule = rules->rules_list_head; while (!RULE_IS_NULL(rule)) { if (RULE_IS_GLOBAL(rule) && !(rule->t_flags[tidx] & RULE_TFLAGS_MATCH)) { rule->ns->t_flags[tidx] |= NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL; } rule++; } rule = rules->rules_list_head; while (!RULE_IS_NULL(rule)) { if (rule->t_flags[tidx] & RULE_TFLAGS_MATCH && !(rule->ns->t_flags[tidx] & NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL)) { message = CALLBACK_MSG_RULE_MATCHING; } else { message = CALLBACK_MSG_RULE_NOT_MATCHING; } if (!RULE_IS_PRIVATE(rule)) { switch (callback(message, rule, user_data)) { case CALLBACK_ABORT: result = ERROR_SUCCESS; goto _exit; case CALLBACK_ERROR: result = ERROR_CALLBACK_ERROR; goto _exit; } } rule++; } callback(CALLBACK_MSG_SCAN_FINISHED, NULL, user_data); _exit: yr_modules_unload_all(&context); _yr_rules_clean_matches(rules); if (matches_arena != NULL) yr_arena_destroy(matches_arena); if (context.objects_table != NULL) yr_hash_table_destroy( context.objects_table, (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy); _yr_rules_lock(rules); rules->tidx_mask &= ~(1 << tidx); _yr_rules_unlock(rules); yr_set_tidx(-1); return result; }