int yr_parser_reduce_external( yyscan_t yyscanner, const char* identifier, int8_t instruction) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_EXTERNAL_VARIABLE* external; external = yr_parser_lookup_external_variable(yyscanner, identifier); if (external != NULL) { if (instruction == EXT_BOOL) { compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, EXT_BOOL, PTR_TO_UINT64(external), NULL); } else if (instruction == EXT_INT && external->type == EXTERNAL_VARIABLE_TYPE_INTEGER) { compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, EXT_INT, PTR_TO_UINT64(external), NULL); } else if (instruction == EXT_STR && external->type == EXTERNAL_VARIABLE_TYPE_FIXED_STRING) { compiler->last_result = yr_parser_emit_with_arg_reloc( yyscanner, EXT_STR, PTR_TO_UINT64(external), NULL); } else { yr_compiler_set_error_extra_info(compiler, external->identifier); compiler->last_result = ERROR_INCORRECT_VARIABLE_TYPE; } } return compiler->last_result; }
int yr_parser_emit_pushes_for_strings( yyscan_t yyscanner, const char* identifier) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_STRING* string = compiler->current_rule_strings; const char* string_identifier; const char* target_identifier; int matching = 0; while(!STRING_IS_NULL(string)) { // Don't generate pushes for strings chained to another one, we are // only interested in non-chained strings or the head of the chain. if (string->chained_to == NULL) { string_identifier = string->identifier; target_identifier = identifier; while (*target_identifier != '\0' && *string_identifier != '\0' && *target_identifier == *string_identifier) { target_identifier++; string_identifier++; } if ((*target_identifier == '\0' && *string_identifier == '\0') || *target_identifier == '*') { yr_parser_emit_with_arg_reloc( yyscanner, PUSH, PTR_TO_UINT64(string), NULL); string->g_flags |= STRING_GFLAGS_REFERENCED; matching++; } } string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } if (matching == 0) { yr_compiler_set_error_extra_info(compiler, identifier); compiler->last_result = ERROR_UNDEFINED_STRING; } return compiler->last_result; }
void * grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size, int *handle, int type, int flags) { void *ret; if (flags & (GRUB_MMAP_MALLOC_LOW | GRUB_MMAP_MALLOC_HIGH)) { struct grub_mmap_malign_and_register_closure c; c.align = align; c.size = size; c.highestlow = 0; if (flags & GRUB_MMAP_MALLOC_LOW) { c.min = 0; c.max = 0x100000; } else { c.min = grub_mmap_high; c.max = 0x100000000ll; } /* FIXME: use low-memory mm allocation once it's available. */ grub_mmap_iterate (find_hook, &c); ret = UINT_TO_PTR (c.highestlow); } else ret = grub_memalign (align, size); if (! ret) { *handle = 0; return 0; } *handle = grub_mmap_register (PTR_TO_UINT64 (ret), size, type); if (! *handle) { grub_free (ret); return 0; } return ret; }
void yr_parser_emit_pushes_for_strings( yyscan_t yyscanner, const char* identifier) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_STRING* string = compiler->current_rule_strings; const char* string_identifier; const char* target_identifier; while(!STRING_IS_NULL(string)) { string_identifier = string->identifier; target_identifier = identifier; while (*target_identifier != '\0' && *string_identifier != '\0' && *target_identifier == *string_identifier) { target_identifier++; string_identifier++; } if ((*target_identifier == '\0' && *string_identifier == '\0') || *target_identifier == '*') { yr_parser_emit_with_arg_reloc( yyscanner, PUSH, PTR_TO_UINT64(string), NULL); string->g_flags |= STRING_GFLAGS_REFERENCED; } string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } }
int yr_execute_code( YR_RULES* rules, EVALUATION_CONTEXT* context, int timeout, time_t start_time) { int64_t r1; int64_t r2; int64_t r3; int64_t mem[MEM_SIZE]; int64_t stack[STACK_SIZE]; int32_t sp = 0; uint8_t* ip = rules->code_start; YR_RULE* rule; YR_STRING* string; YR_MATCH* match; YR_EXTERNAL_VARIABLE* external; int i; int found; int count; int result; int flags; int cycle = 0; int tidx = yr_get_tidx(); while(1) { switch(*ip) { case HALT: // When the halt instruction is reached the stack // should be empty. assert(sp == 0); return ERROR_SUCCESS; case PUSH: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); push(r1); break; case POP: pop(r1); break; case CLEAR_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); mem[r1] = 0; break; case ADD_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); pop(r2); mem[r1] += r2; break; case INCR_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); mem[r1]++; break; case PUSH_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); push(mem[r1]); break; case POP_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); pop(mem[r1]); break; case SWAPUNDEF: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); pop(r2); if (r2 != UNDEFINED) push(r2); else push(mem[r1]); break; case JNUNDEF: pop(r1); push(r1); if (r1 != UNDEFINED) { ip = *(uint8_t**)(ip + 1); // ip will be incremented at the end of the loop, // decrement it here to compensate. ip--; } else { ip += sizeof(uint64_t); } break; case JLE: pop(r2); pop(r1); push(r1); push(r2); if (r1 <= r2) { ip = *(uint8_t**)(ip + 1); // ip will be incremented at the end of the loop, // decrement it here to compensate. ip--; } else { ip += sizeof(uint64_t); } break; case AND: pop(r2); pop(r1); push(r1 & r2); break; case OR: pop(r2); pop(r1); push(r1 | r2); break; case NOT: pop(r1); push(!r1); break; case LT: pop(r2); pop(r1); push(comparison(<, r1, r2)); break; case GT: pop(r2); pop(r1); push(comparison(>, r1, r2)); break; case LE: pop(r2); pop(r1); push(comparison(<=, r1, r2)); break; case GE: pop(r2); pop(r1); push(comparison(>=, r1, r2)); break; case EQ: pop(r2); pop(r1); push(comparison(==, r1, r2)); break; case NEQ: pop(r2); pop(r1); push(comparison(!=, r1, r2)); break; case ADD: pop(r2); pop(r1); push(operation(+, r1, r2)); break; case SUB: pop(r2); pop(r1); push(operation(-, r1, r2)); break; case MUL: pop(r2); pop(r1); push(operation(*, r1, r2)); break; case DIV: pop(r2); pop(r1); push(operation(/, r1, r2)); break; case MOD: pop(r2); pop(r1); push(operation(%, r1, r2)); break; case NEG: pop(r1); push(IS_UNDEFINED(r1) ? UNDEFINED : ~r1); break; case SHR: pop(r2); pop(r1); push(operation(>>, r1, r2)); break; case SHL: pop(r2); pop(r1); push(operation(<<, r1, r2)); break; case XOR: pop(r2); pop(r1); push(operation(^, r1, r2)); break; case RULE_PUSH: rule = *(YR_RULE**)(ip + 1); ip += sizeof(uint64_t); push(rule->t_flags[tidx] & RULE_TFLAGS_MATCH ? 1 : 0); break; case RULE_POP: pop(r1); rule = *(YR_RULE**)(ip + 1); ip += sizeof(uint64_t); if (r1) rule->t_flags[tidx] |= RULE_TFLAGS_MATCH; break; case EXT_INT: external = *(YR_EXTERNAL_VARIABLE**)(ip + 1); ip += sizeof(uint64_t); push(external->integer); break; case EXT_STR: external = *(YR_EXTERNAL_VARIABLE**)(ip + 1); ip += sizeof(uint64_t); push(PTR_TO_UINT64(external->string)); break; case EXT_BOOL: external = *(YR_EXTERNAL_VARIABLE**)(ip + 1); ip += sizeof(uint64_t); if (external->type == EXTERNAL_VARIABLE_TYPE_FIXED_STRING || external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) push(external->string[0] != '\0'); else push(external->integer); break; case SFOUND: pop(r1); string = UINT64_TO_PTR(YR_STRING*, r1); push(string->matches[tidx].tail != NULL ? 1 : 0); break; case SFOUND_AT: pop(r2); pop(r1); if (IS_UNDEFINED(r1)) { push(0); break; } string = UINT64_TO_PTR(YR_STRING*, r2); match = string->matches[tidx].head; found = 0; while (match != NULL) { if (r1 == match->offset) { push(1); found = 1; break; } if (r1 < match->offset) break; match = match->next; } if (!found) push(0); break; case SFOUND_IN: pop(r3); pop(r2); pop(r1); if (IS_UNDEFINED(r1) || IS_UNDEFINED(r2)) { push(0); break; } string = UINT64_TO_PTR(YR_STRING*, r3); match = string->matches[tidx].head; found = FALSE; while (match != NULL && !found) { if (match->offset >= r1 && match->offset <= r2) { push(1); found = TRUE; } if (match->offset > r2) break; match = match->next; } if (!found) push(0); break; case SCOUNT: pop(r1); string = UINT64_TO_PTR(YR_STRING*, r1); match = string->matches[tidx].head; found = 0; while (match != NULL) { found++; match = match->next; } push(found); break; case SOFFSET: pop(r2); pop(r1); if (IS_UNDEFINED(r1)) { push(UNDEFINED); break; } string = UINT64_TO_PTR(YR_STRING*, r2); match = string->matches[tidx].head; i = 1; found = FALSE; while (match != NULL && !found) { if (r1 == i) { push(match->offset); found = TRUE; } i++; match = match->next; } if (!found) push(UNDEFINED); break; case OF: found = 0; count = 0; pop(r1); while (r1 != UNDEFINED) { string = UINT64_TO_PTR(YR_STRING*, r1); if (string->matches[tidx].tail != NULL) found++; count++; pop(r1); } pop(r2); if (r2 != UNDEFINED) push(found >= r2 ? 1 : 0); else push(found >= count ? 1 : 0); break; case SIZE: push(context->file_size); break; case ENTRYPOINT: push(context->entry_point); break; case INT8: pop(r1); push(read_int8_t(context->mem_block, r1)); break; case INT16: pop(r1); push(read_int16_t(context->mem_block, r1)); break; case INT32: pop(r1); push(read_int32_t(context->mem_block, r1)); break; case UINT8: pop(r1); push(read_uint8_t(context->mem_block, r1)); break; case UINT16: pop(r1); push(read_uint16_t(context->mem_block, r1)); break; case UINT32: pop(r1); push(read_uint32_t(context->mem_block, r1)); break; case CONTAINS: pop(r2); pop(r1); push(strstr(UINT64_TO_PTR(char*, r1), UINT64_TO_PTR(char*, r2)) != NULL); break; case MATCHES: pop(r3); pop(r2); pop(r1); flags = (int) r3; count = strlen(UINT64_TO_PTR(char*, r1)); if (count == 0) { push(FALSE); break; } result = yr_re_exec( UINT64_TO_PTR(uint8_t*, r2), UINT64_TO_PTR(uint8_t*, r1), count, flags | RE_FLAGS_SCAN, NULL, NULL); push(result >= 0); break; default: // Unknown instruction, this shouldn't happen. assert(FALSE); } if (timeout > 0) // timeout == 0 means no timeout { // Check for timeout every 10 instruction cycles. if (++cycle == 10) { if (difftime(time(NULL), start_time) > timeout) return ERROR_SCAN_TIMEOUT; cycle = 0; } } ip++; } // After executing the code the stack should be empty. assert(sp == 0); return ERROR_SUCCESS; }
int yr_parser_reduce_string_identifier( yyscan_t yyscanner, const char* identifier, int8_t instruction) { YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); if (strcmp(identifier, "$") == 0) { if (compiler->loop_depth > 0) { yr_parser_emit_with_arg( yyscanner, PUSH_M, LOOP_LOCAL_VARS * (compiler->loop_depth - 1), NULL); yr_parser_emit(yyscanner, instruction, NULL); if (instruction != SFOUND) { string = compiler->current_rule_strings; while(!STRING_IS_NULL(string)) { string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; string = yr_arena_next_address( compiler->strings_arena, string, sizeof(YR_STRING)); } } } else { compiler->last_result = ERROR_MISPLACED_ANONYMOUS_STRING; } } else { string = yr_parser_lookup_string(yyscanner, identifier); if (string != NULL) { yr_parser_emit_with_arg_reloc( yyscanner, PUSH, PTR_TO_UINT64(string), NULL); if (instruction != SFOUND) string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH; yr_parser_emit(yyscanner, instruction, NULL); string->g_flags |= STRING_GFLAGS_REFERENCED; } } return compiler->last_result; }
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; }
int yr_execute_code( YR_RULES* rules, YR_SCAN_CONTEXT* context, int timeout, time_t start_time) { int64_t r1; int64_t r2; int64_t r3; int64_t mem[MEM_SIZE]; int64_t stack[STACK_SIZE]; int64_t args[MAX_FUNCTION_ARGS]; int32_t sp = 0; uint8_t* ip = rules->code_start; YR_RULE* rule; YR_STRING* string; YR_MATCH* match; YR_OBJECT* object; YR_OBJECT_FUNCTION* function; char* identifier; char* args_fmt; int i; int found; int count; int result; int cycle = 0; int tidx = yr_get_tidx(); #ifdef PROFILING_ENABLED clock_t start = clock(); #endif while(1) { switch(*ip) { case OP_HALT: // When the halt instruction is reached the stack // should be empty. assert(sp == 0); return ERROR_SUCCESS; case OP_PUSH: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); push(r1); break; case OP_POP: pop(r1); break; case OP_CLEAR_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); mem[r1] = 0; break; case OP_ADD_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); pop(r2); mem[r1] += r2; break; case OP_INCR_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); mem[r1]++; break; case OP_PUSH_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); push(mem[r1]); break; case OP_POP_M: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); pop(mem[r1]); break; case OP_SWAPUNDEF: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); pop(r2); if (r2 != UNDEFINED) push(r2); else push(mem[r1]); break; case OP_JNUNDEF: pop(r1); push(r1); if (r1 != UNDEFINED) { ip = *(uint8_t**)(ip + 1); // ip will be incremented at the end of the loop, // decrement it here to compensate. ip--; } else { ip += sizeof(uint64_t); } break; case OP_JLE: pop(r2); pop(r1); push(r1); push(r2); if (r1 <= r2) { ip = *(uint8_t**)(ip + 1); // ip will be incremented at the end of the loop, // decrement it here to compensate. ip--; } else { ip += sizeof(uint64_t); } break; case OP_AND: pop(r2); pop(r1); if (IS_UNDEFINED(r1) || IS_UNDEFINED(r2)) push(0); else push(r1 && r2); break; case OP_OR: pop(r2); pop(r1); if (IS_UNDEFINED(r1)) push(r2); else if (IS_UNDEFINED(r2)) push(r1); else push(r1 || r2); break; case OP_NOT: pop(r1); if (IS_UNDEFINED(r1)) push(UNDEFINED); else push(!r1); break; case OP_LT: pop(r2); pop(r1); push(COMPARISON(<, r1, r2)); break; case OP_GT: pop(r2); pop(r1); push(COMPARISON(>, r1, r2)); break; case OP_LE: pop(r2); pop(r1); push(COMPARISON(<=, r1, r2)); break; case OP_GE: pop(r2); pop(r1); push(COMPARISON(>=, r1, r2)); break; case OP_EQ: pop(r2); pop(r1); push(COMPARISON(==, r1, r2)); break; case OP_NEQ: pop(r2); pop(r1); push(COMPARISON(!=, r1, r2)); break; case OP_SZ_EQ: pop(r2); pop(r1); if (IS_UNDEFINED(r1) || IS_UNDEFINED(r2)) push(UNDEFINED); else push(strcmp(UINT64_TO_PTR(char*, r1), UINT64_TO_PTR(char*, r2)) == 0); break; case OP_SZ_NEQ: pop(r2); pop(r1); if (IS_UNDEFINED(r1) || IS_UNDEFINED(r2)) push(UNDEFINED); else push(strcmp(UINT64_TO_PTR(char*, r1), UINT64_TO_PTR(char*, r2)) != 0); break; case OP_SZ_TO_BOOL: pop(r1); if (IS_UNDEFINED(r1)) push(UNDEFINED); else push(strlen(UINT64_TO_PTR(char*, r1)) > 0); break; case OP_ADD: pop(r2); pop(r1); push(OPERATION(+, r1, r2)); break; case OP_SUB: pop(r2); pop(r1); push(OPERATION(-, r1, r2)); break; case OP_MUL: pop(r2); pop(r1); push(OPERATION(*, r1, r2)); break; case OP_DIV: pop(r2); pop(r1); push(OPERATION(/, r1, r2)); break; case OP_MOD: pop(r2); pop(r1); push(OPERATION(%, r1, r2)); break; case OP_SHR: pop(r2); pop(r1); push(OPERATION(>>, r1, r2)); break; case OP_SHL: pop(r2); pop(r1); push(OPERATION(<<, r1, r2)); break; case OP_BITWISE_NOT: pop(r1); push(IS_UNDEFINED(r1) ? UNDEFINED : ~r1); break; case OP_BITWISE_AND: pop(r2); pop(r1); push(OPERATION(&, r1, r2)); break; case OP_BITWISE_OR: pop(r2); pop(r1); push(OPERATION(|, r1, r2)); break; case OP_BITWISE_XOR: pop(r2); pop(r1); push(OPERATION(^, r1, r2)); break; case OP_PUSH_RULE: rule = *(YR_RULE**)(ip + 1); ip += sizeof(uint64_t); push(rule->t_flags[tidx] & RULE_TFLAGS_MATCH ? 1 : 0); break; case OP_MATCH_RULE: pop(r1); rule = *(YR_RULE**)(ip + 1); ip += sizeof(uint64_t); if (!IS_UNDEFINED(r1) && r1) rule->t_flags[tidx] |= RULE_TFLAGS_MATCH; #ifdef PROFILING_ENABLED rule->clock_ticks += clock() - start; start = clock(); #endif break; case OP_OBJ_LOAD: identifier = *(char**)(ip + 1); ip += sizeof(uint64_t); object = (YR_OBJECT*) yr_hash_table_lookup( context->objects_table, identifier, NULL); assert(object != NULL); push(PTR_TO_UINT64(object)); break; case OP_OBJ_FIELD: pop(r1); identifier = *(char**)(ip + 1); ip += sizeof(uint64_t); if (IS_UNDEFINED(r1)) { push(UNDEFINED); break; } object = UINT64_TO_PTR(YR_OBJECT*, r1); object = yr_object_lookup_field(object, identifier); assert(object != NULL); push(PTR_TO_UINT64(object)); break; case OP_OBJ_VALUE: pop(r1); if (IS_UNDEFINED(r1)) { push(UNDEFINED); break; } object = UINT64_TO_PTR(YR_OBJECT*, r1); switch(object->type) { case OBJECT_TYPE_INTEGER: push(((YR_OBJECT_INTEGER*) object)->value); break; case OBJECT_TYPE_STRING: if (((YR_OBJECT_STRING*) object)->value != NULL) push(PTR_TO_UINT64(((YR_OBJECT_STRING*) object)->value)); else push(UNDEFINED); break; default: assert(FALSE); } break; case OP_INDEX_ARRAY: pop(r1); // index pop(r2); // array if (IS_UNDEFINED(r1)) { push(UNDEFINED); break; } object = UINT64_TO_PTR(YR_OBJECT*, r2); assert(object->type == OBJECT_TYPE_ARRAY); object = yr_object_array_get_item(object, 0, r1); if (object != NULL) push(PTR_TO_UINT64(object)); else push(UNDEFINED); break; case OP_LOOKUP_DICT: pop(r1); // key pop(r2); // dictionary if (IS_UNDEFINED(r1)) { push(UNDEFINED); break; } object = UINT64_TO_PTR(YR_OBJECT*, r2); assert(object->type == OBJECT_TYPE_DICTIONARY); object = yr_object_dict_get_item( object, 0, UINT64_TO_PTR(const char*, r1)); if (object != NULL) push(PTR_TO_UINT64(object)); else push(UNDEFINED); break; case OP_CALL: args_fmt = *(char**)(ip + 1); ip += sizeof(uint64_t); i = strlen(args_fmt); // pop arguments from stack and copy them to args array while (i > 0) { pop(args[i - 1]); i--; } pop(r2); function = UINT64_TO_PTR(YR_OBJECT_FUNCTION*, r2); result = ERROR_INTERNAL_FATAL_ERROR; for (i = 0; i < MAX_OVERLOADED_FUNCTIONS; i++) { if (function->prototypes[i].arguments_fmt == NULL) break; if (strcmp(function->prototypes[i].arguments_fmt, args_fmt) == 0) { result = function->prototypes[i].code( (void*) args, context, function); break; } } assert(i < MAX_OVERLOADED_FUNCTIONS); if (result == ERROR_SUCCESS) push(PTR_TO_UINT64(function->return_obj)); else return result; break; case OP_STR_FOUND: pop(r1); string = UINT64_TO_PTR(YR_STRING*, r1); push(string->matches[tidx].tail != NULL ? 1 : 0); break; case OP_STR_FOUND_AT: pop(r2); pop(r1); if (IS_UNDEFINED(r1)) { push(0); break; } string = UINT64_TO_PTR(YR_STRING*, r2); match = string->matches[tidx].head; found = 0; while (match != NULL) { if (r1 == match->base + match->offset) { push(1); found = 1; break; } if (r1 < match->base + match->offset) break; match = match->next; } if (!found) push(0); break; case OP_STR_FOUND_IN: pop(r3); pop(r2); pop(r1); if (IS_UNDEFINED(r1) || IS_UNDEFINED(r2)) { push(UNDEFINED); break; } string = UINT64_TO_PTR(YR_STRING*, r3); match = string->matches[tidx].head; found = FALSE; while (match != NULL && !found) { if (match->base + match->offset >= r1 && match->base + match->offset <= r2) { push(1); found = TRUE; } if (match->base + match->offset > r2) break; match = match->next; } if (!found) push(0); break; case OP_STR_COUNT: pop(r1); string = UINT64_TO_PTR(YR_STRING*, r1); push(string->matches[tidx].count); break; case OP_STR_OFFSET: pop(r2); pop(r1); if (IS_UNDEFINED(r1)) { push(UNDEFINED); break; } string = UINT64_TO_PTR(YR_STRING*, r2); match = string->matches[tidx].head; i = 1; found = FALSE; while (match != NULL && !found) { if (r1 == i) { push(match->base + match->offset); found = TRUE; } i++; match = match->next; } if (!found) push(UNDEFINED); break; case OP_OF: found = 0; count = 0; pop(r1); while (r1 != UNDEFINED) { string = UINT64_TO_PTR(YR_STRING*, r1); if (string->matches[tidx].tail != NULL) found++; count++; pop(r1); } pop(r2); if (r2 != UNDEFINED) push(found >= r2 ? 1 : 0); else push(found >= count ? 1 : 0); break; case OP_FILESIZE: push(context->file_size); break; case OP_ENTRYPOINT: push(context->entry_point); break; case OP_INT8: pop(r1); push(read_int8_t(context->mem_block, r1)); break; case OP_INT16: pop(r1); push(read_int16_t(context->mem_block, r1)); break; case OP_INT32: pop(r1); push(read_int32_t(context->mem_block, r1)); break; case OP_UINT8: pop(r1); push(read_uint8_t(context->mem_block, r1)); break; case OP_UINT16: pop(r1); push(read_uint16_t(context->mem_block, r1)); break; case OP_UINT32: pop(r1); push(read_uint32_t(context->mem_block, r1)); break; case OP_CONTAINS: pop(r2); pop(r1); if (IS_UNDEFINED(r1) || IS_UNDEFINED(r2)) push(UNDEFINED); else push(strstr(UINT64_TO_PTR(char*, r1), UINT64_TO_PTR(char*, r2)) != NULL); break; case OP_IMPORT: r1 = *(uint64_t*)(ip + 1); ip += sizeof(uint64_t); FAIL_ON_ERROR(yr_modules_load( UINT64_TO_PTR(char*, r1), context)); break; case OP_MATCHES: pop(r2); pop(r1); count = strlen(UINT64_TO_PTR(char*, r1)); if (count == 0) { push(FALSE); break; } result = yr_re_exec( UINT64_TO_PTR(uint8_t*, r2), UINT64_TO_PTR(uint8_t*, r1), count, RE_FLAGS_SCAN, NULL, NULL); push(result >= 0); break; default: // Unknown instruction, this shouldn't happen. assert(FALSE); } if (timeout > 0) // timeout == 0 means no timeout { // Check for timeout every 10 instruction cycles. if (++cycle == 10) { if (difftime(time(NULL), start_time) > timeout) return ERROR_SCAN_TIMEOUT; cycle = 0; } } ip++; } // After executing the code the stack should be empty. assert(sp == 0); return ERROR_SUCCESS; }
/* Write value (pointer to memory PLUS_HANDLE) - (pointer to memory MINUS_HANDLE) + VALUE to ADDR assuming that the size SIZE bytes. If PTV_NEEDED is 1 then announce it to runtime that this value needs to be recomputed before going to virtual mode */ grub_err_t grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle, int minus_handle, int ptv_needed, int size) { /* Announce relocator to runtime */ if (ptv_needed) { struct grub_efiemu_ptv_rel *ptv_rels = grub_efiemu_mm_obtain_request (ptv_handle); if (ptv_needed && ptv_written >= ptv_alloc) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "your module didn't declare efiemu " " relocators correctly"); if (minus_handle) ptv_rels[ptv_written].minustype = grub_efiemu_mm_get_type (minus_handle); else ptv_rels[ptv_written].minustype = 0; if (plus_handle) ptv_rels[ptv_written].plustype = grub_efiemu_mm_get_type (plus_handle); else ptv_rels[ptv_written].plustype = 0; ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr); ptv_rels[ptv_written].size = size; ptv_written++; /* memset next value to zero to mark the end */ grub_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written])); } /* Compute the value */ if (minus_handle) value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle)); if (plus_handle) value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle)); /* Write the value */ switch (size) { case 8: *((grub_uint64_t *) addr) = value; break; case 4: *((grub_uint32_t *) addr) = value; break; case 2: *((grub_uint16_t *) addr) = value; break; case 1: *((grub_uint8_t *) addr) = value; break; default: return grub_error (GRUB_ERR_BAD_ARGUMENT, "wrong symbol size"); } return GRUB_ERR_NONE; }
/* Really allocate the memory */ static grub_err_t efiemu_alloc_requests (void) { grub_size_t align_overhead = 0; grub_uint8_t *curptr, *typestart; struct grub_efiemu_memrequest *cur; grub_size_t total_alloc = 0; unsigned i; /* Order of memory regions */ grub_efi_memory_type_t reqorder[] = { /* First come regions usable by OS*/ GRUB_EFI_LOADER_CODE, GRUB_EFI_LOADER_DATA, GRUB_EFI_BOOT_SERVICES_CODE, GRUB_EFI_BOOT_SERVICES_DATA, GRUB_EFI_CONVENTIONAL_MEMORY, GRUB_EFI_ACPI_RECLAIM_MEMORY, /* Then memory used by runtime */ /* This way all our regions are in a single block */ GRUB_EFI_RUNTIME_SERVICES_CODE, GRUB_EFI_RUNTIME_SERVICES_DATA, GRUB_EFI_ACPI_MEMORY_NVS, /* And then unavailable memory types. This is more for a completeness. You should double think before allocating memory of any of these types */ GRUB_EFI_UNUSABLE_MEMORY, GRUB_EFI_MEMORY_MAPPED_IO, GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE, GRUB_EFI_PAL_CODE }; /* Compute total memory needed */ for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++) { align_overhead = GRUB_EFIEMU_PAGESIZE - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE); if (align_overhead == GRUB_EFIEMU_PAGESIZE) align_overhead = 0; total_alloc += requested_memory[reqorder[i]] + align_overhead; } /* Allocate the whole memory in one block */ resident_memory = grub_memalign (GRUB_EFIEMU_PAGESIZE, total_alloc); if (!resident_memory) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate resident memory"); /* Split the memory into blocks by type */ curptr = resident_memory; for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++) { if (!requested_memory[reqorder[i]]) continue; typestart = curptr; /* Write pointers to requests */ for (cur = memrequests; cur; cur = cur->next) if (cur->type == reqorder[i]) { curptr = ((grub_uint8_t *)curptr) + cur->align_overhead; cur->val = curptr; curptr = ((grub_uint8_t *)curptr) + cur->size; } /* Ensure that the regions are page-aligned */ align_overhead = GRUB_EFIEMU_PAGESIZE - (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE); if (align_overhead == GRUB_EFIEMU_PAGESIZE) align_overhead = 0; curptr = ((grub_uint8_t *)curptr) + align_overhead; /* Add the region to memory map */ grub_efiemu_add_to_mmap (PTR_TO_UINT64 (typestart), curptr - typestart, reqorder[i]); } return GRUB_ERR_NONE; }