int yr_parser_reduce_import( yyscan_t yyscanner, SIZED_STRING* module_name) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_OBJECT* module_structure; char* name; module_structure = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, module_name->c_string, compiler->current_namespace->name); // if module already imported, do nothing if (module_structure != NULL) return ERROR_SUCCESS; compiler->last_result = yr_object_create( OBJECT_TYPE_STRUCTURE, module_name->c_string, NULL, &module_structure); if (compiler->last_result == ERROR_SUCCESS) compiler->last_result = yr_hash_table_add( compiler->objects_table, module_name->c_string, compiler->current_namespace->name, module_structure); if (compiler->last_result == ERROR_SUCCESS) { compiler->last_result = yr_modules_do_declarations( module_name->c_string, module_structure); if (compiler->last_result == ERROR_UNKNOWN_MODULE) yr_compiler_set_error_extra_info(compiler, module_name->c_string); } if (compiler->last_result == ERROR_SUCCESS) compiler->last_result = yr_arena_write_string( compiler->sz_arena, module_name->c_string, &name); if (compiler->last_result == ERROR_SUCCESS) compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, OP_IMPORT, PTR_TO_INT64(name), NULL, NULL); return compiler->last_result; }
int yr_compiler_define_string_variable( YR_COMPILER* compiler, const char* identifier, const char* value) { YR_OBJECT* object; YR_EXTERNAL_VARIABLE* external; char* id = NULL; char* val = NULL; compiler->last_result = ERROR_SUCCESS; FAIL_ON_COMPILER_ERROR(yr_arena_write_string( compiler->sz_arena, identifier, &id)); FAIL_ON_COMPILER_ERROR(yr_arena_write_string( compiler->sz_arena, value, &val)); FAIL_ON_COMPILER_ERROR(yr_arena_allocate_struct( compiler->externals_arena, sizeof(YR_EXTERNAL_VARIABLE), (void**) &external, offsetof(YR_EXTERNAL_VARIABLE, identifier), offsetof(YR_EXTERNAL_VARIABLE, string), EOL)); external->type = EXTERNAL_VARIABLE_TYPE_STRING; external->identifier = id; external->integer = 0; external->string = val; FAIL_ON_COMPILER_ERROR(yr_object_from_external_variable( external, &object)); FAIL_ON_COMPILER_ERROR(yr_hash_table_add( compiler->objects_table, external->identifier, NULL, (void*) object)); return compiler->last_result; }
YR_API int yr_compiler_define_float_variable( YR_COMPILER* compiler, const char* identifier, double value) { YR_EXTERNAL_VARIABLE* external; YR_OBJECT* object; char* id; compiler->last_result = ERROR_SUCCESS; FAIL_ON_COMPILER_ERROR(yr_arena_write_string( compiler->sz_arena, identifier, &id)); FAIL_ON_COMPILER_ERROR(yr_arena_allocate_struct( compiler->externals_arena, sizeof(YR_EXTERNAL_VARIABLE), (void**) &external, offsetof(YR_EXTERNAL_VARIABLE, identifier), EOL)); external->type = EXTERNAL_VARIABLE_TYPE_FLOAT; external->identifier = id; external->value.f = value; FAIL_ON_COMPILER_ERROR(yr_object_from_external_variable( external, &object)); FAIL_ON_COMPILER_ERROR(yr_hash_table_add( compiler->objects_table, external->identifier, NULL, (void*) object)); return ERROR_SUCCESS; }
int yr_modules_load( const char* module_name, YR_SCAN_CONTEXT* context) { int i, result; YR_MODULE_IMPORT mi; YR_OBJECT* module_structure = (YR_OBJECT*) yr_hash_table_lookup( context->objects_table, module_name, NULL); // if module_structure != NULL, the module was already // loaded, return successfully without doing nothing. if (module_structure != NULL) return ERROR_SUCCESS; // not loaded yet FAIL_ON_ERROR(yr_object_create( OBJECT_TYPE_STRUCTURE, module_name, NULL, &module_structure)); mi.module_name = module_name; mi.module_data = NULL; mi.module_data_size = 0; result = context->callback( CALLBACK_MSG_IMPORT_MODULE, &mi, context->user_data); if (result == CALLBACK_ERROR) { yr_object_destroy(module_structure); return ERROR_CALLBACK_ERROR; } FAIL_ON_ERROR_WITH_CLEANUP( yr_modules_do_declarations(module_name, module_structure), yr_object_destroy(module_structure)); FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_add( context->objects_table, module_name, NULL, module_structure), yr_object_destroy(module_structure)); for (i = 0; i < sizeof(yr_modules_table) / sizeof(YR_MODULE); i++) { if (strcmp(yr_modules_table[i].name, module_name) == 0) { result = yr_modules_table[i].load( context, module_structure, mi.module_data, mi.module_data_size); if (result != ERROR_SUCCESS) return result; } } result = context->callback( CALLBACK_MSG_MODULE_IMPORTED, module_structure, context->user_data); return ERROR_SUCCESS; }
int yr_parser_reduce_rule_declaration( yyscan_t yyscanner, int32_t flags, const char* identifier, char* tags, YR_STRING* strings, YR_META* metas) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_RULE* rule; YR_STRING* string; if (yr_hash_table_lookup( compiler->rules_table, identifier, compiler->current_namespace->name) != NULL) { // A rule with the same identifier already exists, return the // appropriate error. yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_DUPLICATE_RULE_IDENTIFIER; return compiler->last_result; } // Check for unreferenced (unused) strings. string = compiler->current_rule_strings; while(!STRING_IS_NULL(string)) { // Only the heading fragment in a chain of strings (the one with // chained_to == NULL) must be referenced. All other fragments // are never marked as referenced. if (!STRING_IS_REFERENCED(string) && string->chained_to == NULL) { yr_compiler_set_error_extra_info(compiler, string->identifier); compiler->last_result = ERROR_UNREFERENCED_STRING; break; } string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; compiler->last_result = yr_arena_allocate_struct( compiler->rules_arena, sizeof(YR_RULE), (void**) &rule, offsetof(YR_RULE, identifier), offsetof(YR_RULE, tags), offsetof(YR_RULE, strings), offsetof(YR_RULE, metas), offsetof(YR_RULE, ns), EOL); if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; compiler->last_result = yr_arena_write_string( compiler->sz_arena, identifier, &rule->identifier); if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, RULE_POP, PTR_TO_UINT64(rule), NULL); if (compiler->last_result != ERROR_SUCCESS) return compiler->last_result; rule->g_flags = flags | compiler->current_rule_flags; rule->tags = tags; rule->strings = strings; rule->metas = metas; rule->ns = compiler->current_namespace; compiler->current_rule_flags = 0; compiler->current_rule_strings = NULL; yr_hash_table_add( compiler->rules_table, identifier, compiler->current_namespace->name, (void*) rule); return compiler->last_result; }
YR_RULE* yr_parser_reduce_rule_declaration_phase_1( yyscan_t yyscanner, int32_t flags, const char* identifier) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_RULE* rule = NULL; if (yr_hash_table_lookup( compiler->rules_table, identifier, compiler->current_namespace->name) != NULL || yr_hash_table_lookup( compiler->objects_table, identifier, compiler->current_namespace->name) != NULL) { // A rule or variable with the same identifier already exists, return the // appropriate error. yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_DUPLICATED_IDENTIFIER; return NULL; } compiler->last_result = yr_arena_allocate_struct( compiler->rules_arena, sizeof(YR_RULE), (void**) &rule, offsetof(YR_RULE, identifier), offsetof(YR_RULE, tags), offsetof(YR_RULE, strings), offsetof(YR_RULE, metas), offsetof(YR_RULE, ns), EOL); if (compiler->last_result != ERROR_SUCCESS) return NULL; rule->g_flags = flags; rule->ns = compiler->current_namespace; #ifdef PROFILING_ENABLED rule->clock_ticks = 0; #endif compiler->last_result = yr_arena_write_string( compiler->sz_arena, identifier, (char**) &rule->identifier); if (compiler->last_result != ERROR_SUCCESS) return NULL; compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, OP_INIT_RULE, PTR_TO_INT64(rule), NULL, NULL); if (compiler->last_result == ERROR_SUCCESS) compiler->last_result = yr_hash_table_add( compiler->rules_table, identifier, compiler->current_namespace->name, (void*) rule); // Clean strings_table as we are starting to parse a new rule. yr_hash_table_clean(compiler->strings_table, NULL); compiler->current_rule = rule; return rule; }
YR_STRING* yr_parser_reduce_string_declaration( yyscan_t yyscanner, int32_t string_flags, const char* identifier, SIZED_STRING* str) { int min_atom_quality; int min_atom_quality_aux; int re_flags = 0; int32_t min_gap; int32_t max_gap; char message[512]; YR_COMPILER* compiler = yyget_extra(yyscanner); YR_STRING* string = NULL; YR_STRING* aux_string; YR_STRING* prev_string; RE* re = NULL; RE* remainder_re; RE_ERROR re_error; // Determine if a string with the same identifier was already defined // by searching for the identifier in string_table. string = yr_hash_table_lookup( compiler->strings_table, identifier, NULL); if (string != NULL) { compiler->last_result = ERROR_DUPLICATED_STRING_IDENTIFIER; yr_compiler_set_error_extra_info(compiler, identifier); goto _exit; } // Empty strings are now allowed if (str->length == 0) { compiler->last_result = ERROR_EMPTY_STRING; yr_compiler_set_error_extra_info(compiler, identifier); goto _exit; } if (str->flags & SIZED_STRING_FLAGS_NO_CASE) string_flags |= STRING_GFLAGS_NO_CASE; if (str->flags & SIZED_STRING_FLAGS_DOT_ALL) re_flags |= RE_FLAGS_DOT_ALL; if (strcmp(identifier,"$") == 0) string_flags |= STRING_GFLAGS_ANONYMOUS; if (!(string_flags & STRING_GFLAGS_WIDE)) string_flags |= STRING_GFLAGS_ASCII; if (string_flags & STRING_GFLAGS_NO_CASE) re_flags |= RE_FLAGS_NO_CASE; // The STRING_GFLAGS_SINGLE_MATCH flag indicates that finding // a single match for the string is enough. This is true in // most cases, except when the string count (#) and string offset (@) // operators are used. All strings are marked STRING_FLAGS_SINGLE_MATCH // initially, and unmarked later if required. string_flags |= STRING_GFLAGS_SINGLE_MATCH; // The STRING_GFLAGS_FIXED_OFFSET indicates that the string doesn't // need to be searched all over the file because the user is using the // "at" operator. The string must be searched at a fixed offset in the // file. All strings are marked STRING_GFLAGS_FIXED_OFFSET initially, // and unmarked later if required. string_flags |= STRING_GFLAGS_FIXED_OFFSET; if (string_flags & STRING_GFLAGS_HEXADECIMAL || string_flags & STRING_GFLAGS_REGEXP) { if (string_flags & STRING_GFLAGS_HEXADECIMAL) compiler->last_result = yr_re_parse_hex( str->c_string, re_flags, &re, &re_error); else compiler->last_result = yr_re_parse( str->c_string, re_flags, &re, &re_error); if (compiler->last_result != ERROR_SUCCESS) { snprintf( message, sizeof(message), "invalid %s \"%s\": %s", (string_flags & STRING_GFLAGS_HEXADECIMAL) ? "hex string" : "regular expression", identifier, re_error.message); yr_compiler_set_error_extra_info( compiler, message); goto _exit; } if (re->flags & RE_FLAGS_FAST_HEX_REGEXP) string_flags |= STRING_GFLAGS_FAST_HEX_REGEXP; // Regular expressions in the strings section can't mix greedy and ungreedy // quantifiers like .* and .*?. That's because these regular expressions can // be matched forwards and/or backwards depending on the atom found, and we // need the regexp to be all-greedy or all-ungreedy to be able to properly // calculate the length of the match. if ((re->flags & RE_FLAGS_GREEDY) && (re->flags & RE_FLAGS_UNGREEDY)) { compiler->last_result = ERROR_INVALID_REGULAR_EXPRESSION; yr_compiler_set_error_extra_info(compiler, "greedy and ungreedy quantifiers can't be mixed in a regular " "expression"); goto _exit; } if (re->flags & RE_FLAGS_GREEDY) string_flags |= STRING_GFLAGS_GREEDY_REGEXP; if (yr_re_contains_dot_star(re)) { snprintf( message, sizeof(message), "%s contains .*, consider using .{N} with a reasonable value for N", identifier); yywarning(yyscanner, message); } compiler->last_result = yr_re_split_at_chaining_point( re, &re, &remainder_re, &min_gap, &max_gap); if (compiler->last_result != ERROR_SUCCESS) goto _exit; compiler->last_result = _yr_parser_write_string( identifier, string_flags, compiler, NULL, re, &string, &min_atom_quality); if (compiler->last_result != ERROR_SUCCESS) goto _exit; if (remainder_re != NULL) { string->g_flags |= STRING_GFLAGS_CHAIN_TAIL | STRING_GFLAGS_CHAIN_PART; string->chain_gap_min = min_gap; string->chain_gap_max = max_gap; } // Use "aux_string" from now on, we want to keep the value of "string" // because it will returned. aux_string = string; while (remainder_re != NULL) { // Destroy regexp pointed by 're' before yr_re_split_at_jmp // overwrites 're' with another value. yr_re_destroy(re); compiler->last_result = yr_re_split_at_chaining_point( remainder_re, &re, &remainder_re, &min_gap, &max_gap); if (compiler->last_result != ERROR_SUCCESS) goto _exit; prev_string = aux_string; compiler->last_result = _yr_parser_write_string( identifier, string_flags, compiler, NULL, re, &aux_string, &min_atom_quality_aux); if (compiler->last_result != ERROR_SUCCESS) goto _exit; if (min_atom_quality_aux < min_atom_quality) min_atom_quality = min_atom_quality_aux; aux_string->g_flags |= STRING_GFLAGS_CHAIN_PART; aux_string->chain_gap_min = min_gap; aux_string->chain_gap_max = max_gap; prev_string->chained_to = aux_string; // prev_string is now chained to aux_string, an string chained // to another one can't have a fixed offset, only the head of the // string chain can have a fixed offset. prev_string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET; } } else { compiler->last_result = _yr_parser_write_string( identifier, string_flags, compiler, str, NULL, &string, &min_atom_quality); if (compiler->last_result != ERROR_SUCCESS) goto _exit; } compiler->last_result = yr_hash_table_add( compiler->strings_table, identifier, NULL, string); if (compiler->last_result != ERROR_SUCCESS) goto _exit; if (min_atom_quality < 3 && compiler->callback != NULL) { snprintf( message, sizeof(message), "%s is slowing down scanning%s", string->identifier, min_atom_quality < 2 ? " (critical!)" : ""); yywarning(yyscanner, message); } _exit: if (re != NULL) yr_re_destroy(re); if (compiler->last_result != ERROR_SUCCESS) return NULL; return string; }
int yr_parser_reduce_rule_declaration_phase_1( yyscan_t yyscanner, int32_t flags, const char* identifier, YR_RULE** rule) { YR_FIXUP *fixup; YR_INIT_RULE_ARGS *init_rule_args; YR_COMPILER* compiler = yyget_extra(yyscanner); *rule = NULL; if (yr_hash_table_lookup( compiler->rules_table, identifier, compiler->current_namespace->name) != NULL || yr_hash_table_lookup( compiler->objects_table, identifier, NULL) != NULL) { // A rule or variable with the same identifier already exists, return the // appropriate error. yr_compiler_set_error_extra_info(compiler, identifier); return ERROR_DUPLICATED_IDENTIFIER; } FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->rules_arena, sizeof(YR_RULE), (void**) rule, offsetof(YR_RULE, identifier), offsetof(YR_RULE, tags), offsetof(YR_RULE, strings), offsetof(YR_RULE, metas), offsetof(YR_RULE, ns), EOL)) (*rule)->g_flags = flags; (*rule)->ns = compiler->current_namespace; (*rule)->num_atoms = 0; #ifdef PROFILING_ENABLED (*rule)->time_cost = 0; memset( (*rule)->time_cost_per_thread, 0, sizeof((*rule)->time_cost_per_thread)); #endif FAIL_ON_ERROR(yr_arena_write_string( compiler->sz_arena, identifier, (char**) &(*rule)->identifier)); FAIL_ON_ERROR(yr_parser_emit( yyscanner, OP_INIT_RULE, NULL)); FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->code_arena, sizeof(YR_INIT_RULE_ARGS), (void**) &init_rule_args, offsetof(YR_INIT_RULE_ARGS, rule), offsetof(YR_INIT_RULE_ARGS, jmp_addr), EOL)); init_rule_args->rule = *rule; // jmp_addr holds the address to jump to when we want to skip the code for // the rule. It is iniatialized as NULL at this point because we don't know // the address until emmiting the code for the rule's condition. The address // is set in yr_parser_reduce_rule_declaration_phase_2. init_rule_args->jmp_addr = NULL; // Create a fixup entry for the jump and push it in the stack fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) return ERROR_INSUFFICIENT_MEMORY; fixup->address = (void*) &(init_rule_args->jmp_addr); fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; // Clean strings_table as we are starting to parse a new rule. yr_hash_table_clean(compiler->strings_table, NULL); FAIL_ON_ERROR(yr_hash_table_add( compiler->rules_table, identifier, compiler->current_namespace->name, (void*) *rule)); compiler->current_rule = *rule; return ERROR_SUCCESS; }
int yr_parser_reduce_import( yyscan_t yyscanner, SIZED_STRING* module_name) { int result; YR_COMPILER* compiler = yyget_extra(yyscanner); YR_OBJECT* module_structure; char* name; if (!_yr_parser_valid_module_name(module_name)) { yr_compiler_set_error_extra_info(compiler, module_name->c_string); return ERROR_INVALID_MODULE_NAME; } module_structure = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, module_name->c_string, compiler->current_namespace->name); // if module already imported, do nothing if (module_structure != NULL) return ERROR_SUCCESS; FAIL_ON_ERROR(yr_object_create( OBJECT_TYPE_STRUCTURE, module_name->c_string, NULL, &module_structure)); FAIL_ON_ERROR(yr_hash_table_add( compiler->objects_table, module_name->c_string, compiler->current_namespace->name, module_structure)); result = yr_modules_do_declarations( module_name->c_string, module_structure); if (result == ERROR_UNKNOWN_MODULE) yr_compiler_set_error_extra_info(compiler, module_name->c_string); if (result != ERROR_SUCCESS) return result; FAIL_ON_ERROR(yr_arena_write_string( compiler->sz_arena, module_name->c_string, &name)); FAIL_ON_ERROR(yr_parser_emit_with_arg_reloc( yyscanner, OP_IMPORT, name, NULL, NULL)); return ERROR_SUCCESS; }
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; }