Beispiel #1
0
YR_EXTERNAL_VARIABLE* yr_parser_lookup_external_variable(
    yyscan_t yyscanner,
    const char* identifier)
{
  YR_EXTERNAL_VARIABLE* external;
  YR_COMPILER* compiler = yyget_extra(yyscanner);
  int i;

  external = (YR_EXTERNAL_VARIABLE*) yr_arena_base_address(
      compiler->externals_arena);

  for (i = 0; i < compiler->externals_count; i++)
  {
    if (strcmp(external->identifier, identifier) == 0)
      return external;

    external = yr_arena_next_address(
        compiler->externals_arena,
        external,
        sizeof(YR_EXTERNAL_VARIABLE));
  }

  yr_compiler_set_error_extra_info(compiler, identifier);
  compiler->last_result = ERROR_UNDEFINED_IDENTIFIER;

  return NULL;
}
Beispiel #2
0
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,
            OP_PUSH,
            PTR_TO_INT64(string),
            NULL,
            NULL);

        string->g_flags |= STRING_GFLAGS_REFERENCED;
        string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
        matching++;
      }
    }

    string = (YR_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;
}
Beispiel #3
0
YR_STRING* yr_parser_lookup_string(
    yyscan_t yyscanner,
    const char* identifier)
{
  YR_STRING* string;
  YR_COMPILER* compiler = yyget_extra(yyscanner);

  string = compiler->current_rule_strings;

  while(!STRING_IS_NULL(string))
  {
    // If some string $a gets fragmented into multiple chained
    // strings, all those fragments have the same $a identifier
    // but we are interested in the heading fragment, which is
    // that with chained_to == NULL

    if (strcmp(string->identifier, identifier) == 0 &&
        string->chained_to == NULL)
    {
      return string;
    }

    string = yr_arena_next_address(
        compiler->strings_arena,
        string,
        sizeof(YR_STRING));
  }

  yr_compiler_set_error_extra_info(compiler, identifier);
  compiler->last_result = ERROR_UNDEFINED_STRING;

  return NULL;
}
Beispiel #4
0
YR_STRING* yr_parser_lookup_string(
    yyscan_t yyscanner,
    const char* identifier)
{
  YR_STRING* string;
  YR_COMPILER* compiler = yyget_extra(yyscanner);

  string = compiler->current_rule_strings;

  while(!STRING_IS_NULL(string))
  {
    if (strcmp(string->identifier, identifier) == 0)
      return string;

    string = yr_arena_next_address(
        compiler->strings_arena,
        string,
        sizeof(YR_STRING));
  }

  yr_compiler_set_error_extra_info(compiler, identifier);
  compiler->last_result = ERROR_UNDEFINED_STRING;

  return NULL;
}
Beispiel #5
0
int _yr_compiler_set_namespace(
    YR_COMPILER* compiler,
    const char* namespace_)
{
  YR_NAMESPACE* ns;

  char* ns_name;
  int result;
  int i;
  int found;

  ns = (YR_NAMESPACE*) yr_arena_base_address(compiler->namespaces_arena);
  found = FALSE;

  for (i = 0; i < compiler->namespaces_count; i++)
  {
    if (strcmp(ns->name, namespace_) == 0)
    {
      found = TRUE;
      break;
    }

    ns = (YR_NAMESPACE*) yr_arena_next_address(
        compiler->namespaces_arena,
        ns,
        sizeof(YR_NAMESPACE));
  }

  if (!found)
  {
    result = yr_arena_write_string(
        compiler->sz_arena,
        namespace_,
        &ns_name);

    if (result == ERROR_SUCCESS)
      result = yr_arena_allocate_struct(
          compiler->namespaces_arena,
          sizeof(YR_NAMESPACE),
          (void**) &ns,
          offsetof(YR_NAMESPACE, name),
          EOL);

    if (result != ERROR_SUCCESS)
      return result;

    ns->name = ns_name;

    for (i = 0; i < MAX_THREADS; i++)
      ns->t_flags[i] = 0;

    compiler->namespaces_count++;
  }

  compiler->current_namespace = ns;
  return ERROR_SUCCESS;
}
Beispiel #6
0
int yr_parser_reduce_rule_declaration_phase_2(
    yyscan_t yyscanner,
    YR_RULE* rule)
{
  uint32_t max_strings_per_rule;
  uint32_t strings_in_rule = 0;

  YR_COMPILER* compiler = yyget_extra(yyscanner);

  // Check for unreferenced (unused) strings.

  YR_STRING* string = rule->strings;

  yr_get_configuration(
      YR_CONFIG_MAX_STRINGS_PER_RULE,
      (void*) &max_strings_per_rule);

  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;
      return compiler->last_result;
    }

    strings_in_rule++;

    if (strings_in_rule > max_strings_per_rule) {
      yr_compiler_set_error_extra_info(compiler, rule->identifier);
      compiler->last_result = ERROR_TOO_MANY_STRINGS;
      return compiler->last_result;
    }

    string = (YR_STRING*) yr_arena_next_address(
        compiler->strings_arena,
        string,
        sizeof(YR_STRING));
  }

  compiler->last_result = yr_parser_emit_with_arg_reloc(
      yyscanner,
      OP_MATCH_RULE,
      rule,
      NULL,
      NULL);

  return compiler->last_result;
}
Beispiel #7
0
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));
  }
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
int yr_parser_reduce_string_identifier(
    yyscan_t yyscanner,
    const char* identifier,
    uint8_t instruction,
    uint64_t at_offset)
{
  YR_STRING* string;
  YR_COMPILER* compiler = yyget_extra(yyscanner);

  if (strcmp(identifier, "$") == 0) // is an anonymous string ?
  {
    if (compiler->loop_for_of_mem_offset >= 0) // inside a loop ?
    {
      yr_parser_emit_with_arg(
          yyscanner,
          OP_PUSH_M,
          compiler->loop_for_of_mem_offset,
          NULL,
          NULL);

      yr_parser_emit(yyscanner, instruction, NULL);

      string = compiler->current_rule->strings;

      while(!STRING_IS_NULL(string))
      {
        if (instruction != OP_FOUND)
          string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH;

        if (instruction == OP_FOUND_AT)
        {
          // Avoid overwriting any previous fixed offset

          if (string->fixed_offset == UNDEFINED)
            string->fixed_offset = at_offset;

          // If a previous fixed offset was different, disable
          // the STRING_GFLAGS_FIXED_OFFSET flag because we only
          // have room to store a single fixed offset value

          if (string->fixed_offset != at_offset)
            string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
        }
        else
        {
          string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
        }

        string = (YR_STRING*) yr_arena_next_address(
            compiler->strings_arena,
            string,
            sizeof(YR_STRING));
      }
    }
    else
    {
      // Anonymous strings not allowed outside of a loop
      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,
          OP_PUSH,
          PTR_TO_INT64(string),
          NULL,
          NULL);

      if (instruction != OP_FOUND)
        string->g_flags &= ~STRING_GFLAGS_SINGLE_MATCH;

      if (instruction == OP_FOUND_AT)
      {
        // Avoid overwriting any previous fixed offset

        if (string->fixed_offset == UNDEFINED)
          string->fixed_offset = at_offset;

        // If a previous fixed offset was different, disable
        // the STRING_GFLAGS_FIXED_OFFSET flag because we only
        // have room to store a single fixed offset value

        if (string->fixed_offset == UNDEFINED ||
            string->fixed_offset != at_offset)
        {
          string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
        }
      }
      else
      {
        string->g_flags &= ~STRING_GFLAGS_FIXED_OFFSET;
      }

      yr_parser_emit(yyscanner, instruction, NULL);

      string->g_flags |= STRING_GFLAGS_REFERENCED;
    }
  }

  return compiler->last_result;
}
Beispiel #11
0
int yr_parser_reduce_rule_declaration_phase_2(
    yyscan_t yyscanner,
    YR_RULE* rule)
{
  uint32_t max_strings_per_rule;
  uint32_t strings_in_rule = 0;
  uint8_t* nop_inst_addr = NULL;

  int result;

  YR_FIXUP *fixup;
  YR_STRING* string;
  YR_COMPILER* compiler = yyget_extra(yyscanner);

  yr_get_configuration(
      YR_CONFIG_MAX_STRINGS_PER_RULE,
      (void*) &max_strings_per_rule);

  // Show warning if the rule is generating too many atoms. The warning is
  // shown if the number of atoms is greater than 20 times the maximum number
  // of strings allowed for a rule, as 20 is minimum number of atoms generated
  // for a string using *nocase*, *ascii* and *wide* modifiers simultaneosly.

  if (rule->num_atoms > YR_ATOMS_PER_RULE_WARNING_THRESHOLD)
  {
    yywarning(
        yyscanner,
        "rule %s is slowing down scanning",
        rule->identifier);
  }

  // Check for unreferenced (unused) strings.
  string = 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);
      return ERROR_UNREFERENCED_STRING;
    }

    strings_in_rule++;

    if (strings_in_rule > max_strings_per_rule)
    {
      yr_compiler_set_error_extra_info(compiler, rule->identifier);
      return ERROR_TOO_MANY_STRINGS;
    }

    string = (YR_STRING*) yr_arena_next_address(
        compiler->strings_arena,
        string,
        sizeof(YR_STRING));
  }

  result = yr_parser_emit_with_arg_reloc(
      yyscanner,
      OP_MATCH_RULE,
      rule,
      NULL,
      NULL);

  // Generate a do-nothing instruction (NOP) in order to get its address
  // and use it as the destination for the OP_INIT_RULE skip jump. We can not
  // simply use the address of the OP_MATCH_RULE instruction +1 because we
  // can't be sure that the instruction following the OP_MATCH_RULE is going to
  // be in the same arena page. As we don't have a reliable way of getting the
  // address of the next instruction we generate the OP_NOP.

  if (result == ERROR_SUCCESS)
    result = yr_parser_emit(yyscanner, OP_NOP, &nop_inst_addr);

  fixup = compiler->fixup_stack_head;
  *(void**)(fixup->address) = (void*) nop_inst_addr;
  compiler->fixup_stack_head = fixup->next;
  yr_free(fixup);

  return result;
}