Ejemplo n.º 1
0
Archivo: re.c Proyecto: mikalv/yara
int yr_re_compile(
    const char* re_string,
    int flags,
    YR_ARENA* code_arena,
    RE** re,
    RE_ERROR* error)
{
  RE* compiled_re;
  YR_ARENA* arena;

  *re = NULL;

  FAIL_ON_ERROR(yr_re_parse(re_string, flags, &compiled_re, error));

  if (code_arena == NULL)
  {
    FAIL_ON_ERROR_WITH_CLEANUP(
        yr_arena_create(
            RE_MAX_CODE_SIZE,
            ARENA_FLAGS_FIXED_SIZE,
            &arena),
        yr_re_destroy(compiled_re));

    compiled_re->code_arena = arena;
  }
  else
  {
    arena = code_arena;
  }

  FAIL_ON_ERROR_WITH_CLEANUP(
      yr_re_emit_code(compiled_re, arena),
      yr_re_destroy(compiled_re));

  *re = compiled_re;

  return ERROR_SUCCESS;
}
Ejemplo n.º 2
0
Archivo: compiler.c Proyecto: c4nc/yara
YR_API int yr_compiler_create(
    YR_COMPILER** compiler)
{
  int result;
  YR_COMPILER* new_compiler;

  new_compiler = (YR_COMPILER*) yr_calloc(1, sizeof(YR_COMPILER));

  if (new_compiler == NULL)
    return ERROR_INSUFICIENT_MEMORY;

  new_compiler->errors = 0;
  new_compiler->callback = NULL;
  new_compiler->last_error = ERROR_SUCCESS;
  new_compiler->last_error_line = 0;
  new_compiler->error_line = 0;
  new_compiler->last_result = ERROR_SUCCESS;
  new_compiler->file_stack_ptr = 0;
  new_compiler->file_name_stack_ptr = 0;
  new_compiler->fixup_stack_head = NULL;
  new_compiler->allow_includes = 1;
  new_compiler->loop_depth = 0;
  new_compiler->loop_for_of_mem_offset = -1;
  new_compiler->compiled_rules_arena = NULL;
  new_compiler->namespaces_count = 0;
  new_compiler->current_rule = NULL;

  result = yr_hash_table_create(10007, &new_compiler->rules_table);

  if (result == ERROR_SUCCESS)
    result = yr_hash_table_create(10007, &new_compiler->objects_table);

  if (result == ERROR_SUCCESS)
    result = yr_hash_table_create(101, &new_compiler->strings_table);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->sz_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->rules_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->strings_arena);

  if (result == ERROR_SUCCESS)
      result = yr_arena_create(65536, 0, &new_compiler->code_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->re_code_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->externals_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->namespaces_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->metas_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->automaton_arena);

  if (result == ERROR_SUCCESS)
    result = yr_arena_create(65536, 0, &new_compiler->matches_arena);

  if (result == ERROR_SUCCESS)
    result = yr_ac_automaton_create(&new_compiler->automaton);

  if (result == ERROR_SUCCESS)
  {
    *compiler = new_compiler;
  }
  else  // if error, do cleanup
  {
    yr_compiler_destroy(new_compiler);
  }

  return result;
}
Ejemplo n.º 3
0
Archivo: compiler.c Proyecto: c4nc/yara
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
Archivo: exec.c Proyecto: metthal/yara
int yr_execute_code(
    YR_SCAN_CONTEXT* context)
{
  int64_t mem[MEM_SIZE];
  int32_t sp = 0;

  const uint8_t* ip = context->rules->code_start;

  YR_VALUE args[YR_MAX_FUNCTION_ARGS];
  YR_VALUE *stack;
  YR_VALUE r1;
  YR_VALUE r2;
  YR_VALUE r3;

  uint64_t elapsed_time;

  #ifdef PROFILING_ENABLED
  uint64_t start_time;
  YR_RULE* current_rule = NULL;
  #endif

  YR_INIT_RULE_ARGS init_rule_args;

  YR_RULE* rule;
  YR_MATCH* match;
  YR_OBJECT_FUNCTION* function;
  YR_OBJECT** obj_ptr;
  YR_ARENA* obj_arena;

  char* identifier;
  char* args_fmt;

  int i;
  int found;
  int count;
  int result = ERROR_SUCCESS;
  int cycle = 0;
  int tidx = context->tidx;
  int stack_size;

  bool stop = false;

  uint8_t opcode;

  yr_get_configuration(YR_CONFIG_STACK_SIZE, (void*) &stack_size);

  stack = (YR_VALUE*) yr_malloc(stack_size * sizeof(YR_VALUE));

  if (stack == NULL)
    return ERROR_INSUFFICIENT_MEMORY;

  FAIL_ON_ERROR_WITH_CLEANUP(
      yr_arena_create(1024, 0, &obj_arena),
      yr_free(stack));

  #ifdef PROFILING_ENABLED
  start_time = yr_stopwatch_elapsed_us(&context->stopwatch);
  #endif

  #if PARANOID_EXEC
  memset(mem, 0, MEM_SIZE * sizeof(mem[0]));
  #endif

  while(!stop)
  {
    opcode = *ip;
    ip++;

    switch(opcode)
    {
      case OP_NOP:
        break;

      case OP_HALT:
        assert(sp == 0); // When HALT is reached the stack should be empty.
        stop = true;
        break;

      case OP_PUSH:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        push(r1);
        break;

      case OP_POP:
        pop(r1);
        break;

      case OP_CLEAR_M:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        #if PARANOID_EXEC
        ensure_within_mem(r1.i);
        #endif
        mem[r1.i] = 0;
        break;

      case OP_ADD_M:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        #if PARANOID_EXEC
        ensure_within_mem(r1.i);
        #endif
        pop(r2);
        if (!is_undef(r2))
          mem[r1.i] += r2.i;
        break;

      case OP_INCR_M:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        #if PARANOID_EXEC
        ensure_within_mem(r1.i);
        #endif
        mem[r1.i]++;
        break;

      case OP_PUSH_M:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        #if PARANOID_EXEC
        ensure_within_mem(r1.i);
        #endif
        r1.i = mem[r1.i];
        push(r1);
        break;

      case OP_POP_M:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        #if PARANOID_EXEC
        ensure_within_mem(r1.i);
        #endif
        pop(r2);
        mem[r1.i] = r2.i;
        break;

      case OP_SET_M:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        #if PARANOID_EXEC
        ensure_within_mem(r1.i);
        #endif
        pop(r2);
        push(r2);
        if (!is_undef(r2))
          mem[r1.i] = r2.i;
        break;

      case OP_SWAPUNDEF:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);
        #if PARANOID_EXEC
        ensure_within_mem(r1.i);
        #endif
        pop(r2);

        if (is_undef(r2))
        {
          r1.i = mem[r1.i];
          push(r1);
        }
        else
        {
          push(r2);
        }
        break;

      case OP_JNUNDEF:
        pop(r1);
        push(r1);
        ip = jmp_if(!is_undef(r1), ip);
        break;

      case OP_JLE_P:
        pop(r2);
        pop(r1);
        ip = jmp_if(r1.i <= r2.i, ip);
        break;

      case OP_JTRUE:
        pop(r1);
        push(r1);
        ip = jmp_if(!is_undef(r1) && r1.i, ip);
        break;

      case OP_JFALSE:
        pop(r1);
        push(r1);
        ip = jmp_if(is_undef(r1) || !r1.i, ip);
        break;

      case OP_JFALSE_P:
        pop(r1);
        ip = jmp_if(is_undef(r1) || !r1.i, ip);
        break;

      case OP_AND:
        pop(r2);
        pop(r1);

        if (is_undef(r1) || is_undef(r2))
          r1.i = 0;
        else
          r1.i = r1.i && r2.i;

        push(r1);
        break;

      case OP_OR:
        pop(r2);
        pop(r1);

        if (is_undef(r1))
        {
          push(r2);
        }
        else if (is_undef(r2))
        {
          push(r1);
        }
        else
        {
          r1.i = r1.i || r2.i;
          push(r1);
        }
        break;

      case OP_NOT:
        pop(r1);

        if (is_undef(r1))
          r1.i = UNDEFINED;
        else
          r1.i = !r1.i;

        push(r1);
        break;

      case OP_MOD:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        if (r2.i != 0)
          r1.i = r1.i % r2.i;
        else
          r1.i = UNDEFINED;
        push(r1);
        break;

      case OP_SHR:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        if (r2.i < 0)
          r1.i = UNDEFINED;
        else if (r2.i < 64)
          r1.i = r1.i >> r2.i;
        else
          r1.i = 0;
        push(r1);
        break;

      case OP_SHL:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        if (r2.i < 0)
          r1.i = UNDEFINED;
        else if (r2.i < 64)
          r1.i = r1.i << r2.i;
        else
          r1.i = 0;
        push(r1);
        break;

      case OP_BITWISE_NOT:
        pop(r1);
        ensure_defined(r1);
        r1.i = ~r1.i;
        push(r1);
        break;

      case OP_BITWISE_AND:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i & r2.i;
        push(r1);
        break;

      case OP_BITWISE_OR:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i | r2.i;
        push(r1);
        break;

      case OP_BITWISE_XOR:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i ^ r2.i;
        push(r1);
        break;

      case OP_PUSH_RULE:
        rule = *(YR_RULE**)(ip);
        ip += sizeof(uint64_t);
        if (RULE_IS_DISABLED(rule))
          r1.i = UNDEFINED;
        else
          r1.i = rule->t_flags[tidx] & RULE_TFLAGS_MATCH ? 1 : 0;
        push(r1);
        break;

      case OP_INIT_RULE:
        memcpy(&init_rule_args, ip, sizeof(init_rule_args));
        #ifdef PROFILING_ENABLED
        current_rule = init_rule_args.rule;
        #endif
        if (RULE_IS_DISABLED(init_rule_args.rule))
          ip = init_rule_args.jmp_addr;
        else
          ip += sizeof(init_rule_args);
        break;

      case OP_MATCH_RULE:
        pop(r1);
        rule = *(YR_RULE**)(ip);
        ip += sizeof(uint64_t);

        if (!is_undef(r1) && r1.i)
          rule->t_flags[tidx] |= RULE_TFLAGS_MATCH;
        else if (RULE_IS_GLOBAL(rule))
          rule->ns->t_flags[tidx] |= NAMESPACE_TFLAGS_UNSATISFIED_GLOBAL;

        #ifdef PROFILING_ENABLED
        elapsed_time = yr_stopwatch_elapsed_us(&context->stopwatch);
        rule->time_cost_per_thread[tidx] += (elapsed_time - start_time);
        start_time = elapsed_time;
        #endif

        assert(sp == 0); // at this point the stack should be empty.
        break;

      case OP_OBJ_LOAD:
        identifier = *(char**)(ip);
        ip += sizeof(uint64_t);

        r1.o = (YR_OBJECT*) yr_hash_table_lookup(
            context->objects_table,
            identifier,
            NULL);

        assert(r1.o != NULL);
        push(r1);
        break;

      case OP_OBJ_FIELD:
        identifier = *(char**)(ip);
        ip += sizeof(uint64_t);

        pop(r1);
        ensure_defined(r1);

        r1.o = yr_object_lookup_field(r1.o, identifier);

        assert(r1.o != NULL);
        push(r1);
        break;

      case OP_OBJ_VALUE:
        pop(r1);
        ensure_defined(r1);

        #if PARANOID_EXEC
        check_object_canary(r1.o);
        #endif

        switch(r1.o->type)
        {
          case OBJECT_TYPE_INTEGER:
            r1.i = r1.o->value.i;
            break;

          case OBJECT_TYPE_FLOAT:
            if (isnan(r1.o->value.d))
              r1.i = UNDEFINED;
            else
              r1.d = r1.o->value.d;
            break;

          case OBJECT_TYPE_STRING:
            if (r1.o->value.ss == NULL)
              r1.i = UNDEFINED;
            else
              r1.ss = r1.o->value.ss;
            break;

          default:
            assert(false);
        }

        push(r1);
        break;

      case OP_INDEX_ARRAY:
        pop(r1);  // index
        pop(r2);  // array

        ensure_defined(r1);
        ensure_defined(r2);

        assert(r2.o->type == OBJECT_TYPE_ARRAY);

        #if PARANOID_EXEC
        check_object_canary(r2.o);
        #endif

        r1.o = yr_object_array_get_item(r2.o, 0, (int) r1.i);

        if (r1.o == NULL)
          r1.i = UNDEFINED;

        push(r1);
        break;

      case OP_LOOKUP_DICT:
        pop(r1);  // key
        pop(r2);  // dictionary

        ensure_defined(r1);
        ensure_defined(r2);

        assert(r2.o->type == OBJECT_TYPE_DICTIONARY);

        #if PARANOID_EXEC
        check_object_canary(r2.o);
        #endif

        r1.o = yr_object_dict_get_item(
            r2.o, 0, r1.ss->c_string);

        if (r1.o == NULL)
          r1.i = UNDEFINED;

        push(r1);
        break;

      case OP_CALL:
        args_fmt = *(char**)(ip);
        ip += sizeof(uint64_t);

        i = (int) strlen(args_fmt);
        count = 0;

        #if PARANOID_EXEC
        if (i > YR_MAX_FUNCTION_ARGS)
        {
          stop = true;
          result = ERROR_INTERNAL_FATAL_ERROR;
          break;
        }
        #endif

        // pop arguments from stack and copy them to args array

        while (i > 0)
        {
          pop(r1);

          if (is_undef(r1))  // count the number of undefined args
            count++;

          args[i - 1] = r1;
          i--;
        }

        pop(r2);
        ensure_defined(r2);

        #if PARANOID_EXEC
        check_object_canary(r2.o);
        #endif

        if (count > 0)
        {
          // if there are undefined args, result for function call
          // is undefined as well.

          r1.i = UNDEFINED;
          push(r1);
          break;
        }

        function = object_as_function(r2.o);
        result = ERROR_INTERNAL_FATAL_ERROR;

        for (i = 0; i < YR_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(args, context, function);
            break;
          }
        }

        // if i == YR_MAX_OVERLOADED_FUNCTIONS at this point no matching
        // prototype was found, but this shouldn't happen.

        assert(i < YR_MAX_OVERLOADED_FUNCTIONS);

        // make a copy of the returned object and push the copy into the stack
        // function->return_obj can't be pushed because it can change in
        // subsequent calls to the same function.

        if (result == ERROR_SUCCESS)
          result = yr_object_copy(function->return_obj, &r1.o);

        // a pointer to the copied object is stored in a arena in order to
        // free the object before exiting yr_execute_code

        if (result == ERROR_SUCCESS)
          result = yr_arena_write_data(obj_arena, &r1.o, sizeof(r1.o), NULL);

        stop = (result != ERROR_SUCCESS);
        push(r1);
        break;

      case OP_FOUND:
        pop(r1);
        r1.i = r1.s->matches[tidx].tail != NULL ? 1 : 0;
        push(r1);
        break;

      case OP_FOUND_AT:
        pop(r2);
        pop(r1);

        if (is_undef(r1))
        {
          r1.i = 0;
          push(r1);
          break;
        }

        match = r2.s->matches[tidx].head;
        r3.i = false;

        while (match != NULL)
        {
          if (r1.i == match->base + match->offset)
          {
            r3.i = true;
            break;
          }

          if (r1.i < match->base + match->offset)
            break;

          match = match->next;
        }

        push(r3);
        break;

      case OP_FOUND_IN:
        pop(r3);
        pop(r2);
        pop(r1);

        ensure_defined(r1);
        ensure_defined(r2);

        match = r3.s->matches[tidx].head;
        r3.i = false;

        while (match != NULL && !r3.i)
        {
          if (match->base + match->offset >= r1.i &&
              match->base + match->offset <= r2.i)
          {
            r3.i = true;
          }

          if (match->base + match->offset > r2.i)
            break;

          match = match->next;
        }

        push(r3);
        break;

      case OP_COUNT:
        pop(r1);

        #if PARANOID_EXEC
        // Make sure that the string pointer is within the rules arena.
        if (yr_arena_page_for_address(context->rules->arena, r1.p) == NULL)
          return ERROR_INTERNAL_FATAL_ERROR;
        #endif

        r1.i = r1.s->matches[tidx].count;
        push(r1);
        break;

      case OP_OFFSET:
        pop(r2);
        pop(r1);

        ensure_defined(r1);

        match = r2.s->matches[tidx].head;
        i = 1;
        r3.i = UNDEFINED;

        while (match != NULL && r3.i == UNDEFINED)
        {
          if (r1.i == i)
            r3.i = match->base + match->offset;

          i++;
          match = match->next;
        }

        push(r3);
        break;

      case OP_LENGTH:
        pop(r2);
        pop(r1);

        ensure_defined(r1);

        match = r2.s->matches[tidx].head;
        i = 1;
        r3.i = UNDEFINED;

        while (match != NULL && r3.i == UNDEFINED)
        {
          if (r1.i == i)
            r3.i = match->match_length;

          i++;
          match = match->next;
        }

        push(r3);
        break;

      case OP_OF:
        found = 0;
        count = 0;
        pop(r1);

        while (!is_undef(r1))
        {
          if (r1.s->matches[tidx].tail != NULL)
            found++;
          count++;
          pop(r1);
        }

        pop(r2);

        if (is_undef(r2))
          r1.i = found >= count ? 1 : 0;
        else
          r1.i = found >= r2.i ? 1 : 0;

        push(r1);
        break;

      case OP_FILESIZE:
        r1.i = context->file_size;
        push(r1);
        break;

      case OP_ENTRYPOINT:
        r1.i = context->entry_point;
        push(r1);
        break;

      case OP_INT8:
        pop(r1);
        r1.i = read_int8_t_little_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_INT16:
        pop(r1);
        r1.i = read_int16_t_little_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_INT32:
        pop(r1);
        r1.i = read_int32_t_little_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_UINT8:
        pop(r1);
        r1.i = read_uint8_t_little_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_UINT16:
        pop(r1);
        r1.i = read_uint16_t_little_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_UINT32:
        pop(r1);
        r1.i = read_uint32_t_little_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_INT8BE:
        pop(r1);
        r1.i = read_int8_t_big_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_INT16BE:
        pop(r1);
        r1.i = read_int16_t_big_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_INT32BE:
        pop(r1);
        r1.i = read_int32_t_big_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_UINT8BE:
        pop(r1);
        r1.i = read_uint8_t_big_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_UINT16BE:
        pop(r1);
        r1.i = read_uint16_t_big_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_UINT32BE:
        pop(r1);
        r1.i = read_uint32_t_big_endian(context->iterator, (size_t) r1.i);
        push(r1);
        break;

      case OP_CONTAINS:
        pop(r2);
        pop(r1);

        ensure_defined(r1);
        ensure_defined(r2);

        r1.i = memmem(r1.ss->c_string, r1.ss->length,
                      r2.ss->c_string, r2.ss->length) != NULL;
        push(r1);
        break;

      case OP_IMPORT:
        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);

        result = yr_modules_load((char*) r1.p, context);

        if (result != ERROR_SUCCESS)
          stop = true;

        break;

      case OP_MATCHES:

        pop(r2);
        pop(r1);

        ensure_defined(r2);
        ensure_defined(r1);

        if (r1.ss->length == 0)
        {
          r1.i = false;
          push(r1);
          break;
        }

        result = yr_re_exec(
          context,
          (uint8_t*) r2.re->code,
          (uint8_t*) r1.ss->c_string,
          r1.ss->length,
          0,
          r2.re->flags | RE_FLAGS_SCAN,
          NULL,
          NULL,
          &found);

        if (result != ERROR_SUCCESS)
          stop = true;

        r1.i = found >= 0;
        push(r1);
        break;

      case OP_INT_TO_DBL:

        r1.i = *(uint64_t*)(ip);
        ip += sizeof(uint64_t);

        #if PARANOID_EXEC
        if (r1.i > sp || sp - r1.i >= stack_size)
        {
          stop = true;
          result = ERROR_INTERNAL_FATAL_ERROR;
          break;
        }
        #endif

        r2 = stack[sp - r1.i];

        if (is_undef(r2))
          stack[sp - r1.i].i = UNDEFINED;
        else
          stack[sp - r1.i].d = (double) r2.i;
        break;

      case OP_STR_TO_BOOL:
        pop(r1);
        ensure_defined(r1);
        r1.i = r1.ss->length > 0;
        push(r1);
        break;

      case OP_INT_EQ:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i == r2.i;
        push(r1);
        break;

      case OP_INT_NEQ:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i != r2.i;
        push(r1);
        break;

      case OP_INT_LT:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i < r2.i;
        push(r1);
        break;

      case OP_INT_GT:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i > r2.i;
        push(r1);
        break;

      case OP_INT_LE:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i <= r2.i;
        push(r1);
        break;

      case OP_INT_GE:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i >= r2.i;
        push(r1);
        break;

      case OP_INT_ADD:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i + r2.i;
        push(r1);
        break;

      case OP_INT_SUB:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i - r2.i;
        push(r1);
        break;

      case OP_INT_MUL:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.i * r2.i;
        push(r1);
        break;

      case OP_INT_DIV:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        if (r2.i != 0)
          r1.i = r1.i / r2.i;
        else
          r1.i = UNDEFINED;
        push(r1);
        break;

      case OP_INT_MINUS:
        pop(r1);
        ensure_defined(r1);
        r1.i = -r1.i;
        push(r1);
        break;

      case OP_DBL_LT:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.d < r2.d;
        push(r1);
        break;

      case OP_DBL_GT:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.d > r2.d;
        push(r1);
        break;

      case OP_DBL_LE:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.d <= r2.d;
        push(r1);
        break;

      case OP_DBL_GE:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = r1.d >= r2.d;
        push(r1);
        break;

      case OP_DBL_EQ:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = fabs(r1.d - r2.d) < DBL_EPSILON;
        push(r1);
        break;

      case OP_DBL_NEQ:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.i = fabs(r1.d - r2.d) >= DBL_EPSILON;
        push(r1);
        break;

      case OP_DBL_ADD:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.d = r1.d + r2.d;
        push(r1);
        break;

      case OP_DBL_SUB:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.d = r1.d - r2.d;
        push(r1);
        break;

      case OP_DBL_MUL:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.d = r1.d * r2.d;
        push(r1);
        break;

      case OP_DBL_DIV:
        pop(r2);
        pop(r1);
        ensure_defined(r2);
        ensure_defined(r1);
        r1.d = r1.d / r2.d;
        push(r1);
        break;

      case OP_DBL_MINUS:
        pop(r1);
        ensure_defined(r1);
        r1.d = -r1.d;
        push(r1);
        break;

      case OP_STR_EQ:
      case OP_STR_NEQ:
      case OP_STR_LT:
      case OP_STR_LE:
      case OP_STR_GT:
      case OP_STR_GE:

        pop(r2);
        pop(r1);

        ensure_defined(r1);
        ensure_defined(r2);

        switch(opcode)
        {
          case OP_STR_EQ:
            r1.i = (sized_string_cmp(r1.ss, r2.ss) == 0);
            break;
          case OP_STR_NEQ:
            r1.i = (sized_string_cmp(r1.ss, r2.ss) != 0);
            break;
          case OP_STR_LT:
            r1.i = (sized_string_cmp(r1.ss, r2.ss) < 0);
            break;
          case OP_STR_LE:
            r1.i = (sized_string_cmp(r1.ss, r2.ss) <= 0);
            break;
          case OP_STR_GT:
            r1.i = (sized_string_cmp(r1.ss, r2.ss) > 0);
            break;
          case OP_STR_GE:
            r1.i = (sized_string_cmp(r1.ss, r2.ss) >= 0);
            break;
        }

        push(r1);
        break;

      default:
        // Unknown instruction, this shouldn't happen.
        assert(false);
    }

    // Check for timeout every 10 instruction cycles. If timeout == 0 it means
    // no timeout at all.

    if (context->timeout > 0L && ++cycle == 10)
    {
      elapsed_time = yr_stopwatch_elapsed_us(&context->stopwatch);

      if (elapsed_time > context->timeout)
      {
        #ifdef PROFILING_ENABLED
        assert(current_rule != NULL);
        current_rule->time_cost_per_thread[tidx] += elapsed_time - start_time;
        #endif
        result = ERROR_SCAN_TIMEOUT;
        stop = true;
      }

      cycle = 0;
    }
  }
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
Archivo: rules.c Proyecto: dodng/yara
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;
}
Ejemplo n.º 9
0
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;
}