Ejemplo n.º 1
0
int outcheck_ctx_init (hashcat_ctx_t *hashcat_ctx)
{
  folder_config_t *folder_config = hashcat_ctx->folder_config;
  outcheck_ctx_t  *outcheck_ctx  = hashcat_ctx->outcheck_ctx;
  user_options_t  *user_options  = hashcat_ctx->user_options;

  outcheck_ctx->enabled = false;

  if (user_options->keyspace       == true) return 0;
  if (user_options->benchmark      == true) return 0;
  if (user_options->example_hashes == true) return 0;
  if (user_options->speed_only     == true) return 0;
  if (user_options->progress_only  == true) return 0;
  if (user_options->opencl_info    == true) return 0;

  if (user_options->outfile_check_timer == 0) return 0;

  if ((user_options->hash_mode ==  5200) ||
     ((user_options->hash_mode >=  6200) && (user_options->hash_mode <=  6299)) ||
     ((user_options->hash_mode >= 13700) && (user_options->hash_mode <= 13799)) ||
      (user_options->hash_mode ==  9000)) return 0;

  if (user_options->outfile_check_dir == NULL)
  {
    hc_asprintf (&outcheck_ctx->root_directory, "%s/%s.%s", folder_config->session_dir, user_options->session, OUTFILES_DIR);
  }
  else
  {
    outcheck_ctx->root_directory = user_options->outfile_check_dir;
  }

  outcheck_ctx->enabled = true;

  if (hc_path_exist (outcheck_ctx->root_directory) == false)
  {
    if (hc_mkdir (outcheck_ctx->root_directory, 0700) == -1)
    {
      event_log_error (hashcat_ctx, "%s: %s", outcheck_ctx->root_directory, strerror (errno));

      return -1;
    }
  }

  return 0;
}
Ejemplo n.º 2
0
void hashes_init_filename (hashcat_ctx_t *hashcat_ctx)
{
  hashconfig_t         *hashconfig         = hashcat_ctx->hashconfig;
  hashes_t             *hashes             = hashcat_ctx->hashes;
  user_options_t       *user_options       = hashcat_ctx->user_options;
  user_options_extra_t *user_options_extra = hashcat_ctx->user_options_extra;

  char *hash_or_file = user_options_extra->hc_hash;

  /**
   * load hashes, part I: find input mode, count hashes
   */

  if ((user_options->benchmark == false) && (user_options->stdout_flag == false) && (user_options->keyspace == false))
  {
    if (hashconfig->opts_type & OPTS_TYPE_BINARY_HASHFILE)
    {
      hashes->hashlist_mode = HL_MODE_ARG;

      hashes->hashfile = hash_or_file;

      hc_asprintf (&hashes->hashfile_hcdmp, "%s.hcdmp", hashes->hashfile);
    }
    else
    {
      hashes->hashlist_mode = (hc_path_exist (hash_or_file) == true) ? HL_MODE_FILE : HL_MODE_ARG;

      if (hashes->hashlist_mode == HL_MODE_FILE)
      {
        hashes->hashfile = hash_or_file;

        hc_asprintf (&hashes->hashfile_hcdmp, "%s.hcdmp", hashes->hashfile);
      }
    }
  }
  else
  {
    hashes->hashlist_mode = HL_MODE_ARG;
  }
}
Ejemplo n.º 3
0
int mask_ctx_init (hashcat_ctx_t *hashcat_ctx)
{
  mask_ctx_t           *mask_ctx            = hashcat_ctx->mask_ctx;
  user_options_extra_t *user_options_extra  = hashcat_ctx->user_options_extra;
  user_options_t       *user_options        = hashcat_ctx->user_options;

  mask_ctx->enabled = false;

  if (user_options->example_hashes == true) return 0;
  if (user_options->left           == true) return 0;
  if (user_options->opencl_info    == true) return 0;
  if (user_options->show           == true) return 0;
  if (user_options->usage          == true) return 0;
  if (user_options->version        == true) return 0;

  if (user_options->attack_mode == ATTACK_MODE_STRAIGHT) return 0;
  if (user_options->attack_mode == ATTACK_MODE_COMBI)    return 0;

  mask_ctx->enabled = true;

  mask_ctx->root_table_buf   = (hcstat_table_t *) hccalloc (SP_ROOT_CNT,   sizeof (hcstat_table_t));
  mask_ctx->markov_table_buf = (hcstat_table_t *) hccalloc (SP_MARKOV_CNT, sizeof (hcstat_table_t));

  const int rc_setup_tbl = sp_setup_tbl (hashcat_ctx);

  if (rc_setup_tbl == -1) return -1;

  mask_ctx->root_css_buf   = (cs_t *) hccalloc (SP_PW_MAX,           sizeof (cs_t));
  mask_ctx->markov_css_buf = (cs_t *) hccalloc (SP_PW_MAX * CHARSIZ, sizeof (cs_t));

  mask_ctx->css_cnt = 0;
  mask_ctx->css_buf = NULL;

  mask_ctx->mask_from_file = false;

  mask_ctx->masks     = NULL;
  mask_ctx->masks_pos = 0;
  mask_ctx->masks_cnt = 0;

  mask_ctx->mfs = (mf_t *) hccalloc (MAX_MFS, sizeof (mf_t));

  mp_setup_sys (mask_ctx->mp_sys);

  if (user_options->custom_charset_1) { const int rc = mp_setup_usr (hashcat_ctx, mask_ctx->mp_sys, mask_ctx->mp_usr, user_options->custom_charset_1, 0); if (rc == -1) return -1; }
  if (user_options->custom_charset_2) { const int rc = mp_setup_usr (hashcat_ctx, mask_ctx->mp_sys, mask_ctx->mp_usr, user_options->custom_charset_2, 1); if (rc == -1) return -1; }
  if (user_options->custom_charset_3) { const int rc = mp_setup_usr (hashcat_ctx, mask_ctx->mp_sys, mask_ctx->mp_usr, user_options->custom_charset_3, 2); if (rc == -1) return -1; }
  if (user_options->custom_charset_4) { const int rc = mp_setup_usr (hashcat_ctx, mask_ctx->mp_sys, mask_ctx->mp_usr, user_options->custom_charset_4, 3); if (rc == -1) return -1; }

  if (user_options->attack_mode == ATTACK_MODE_BF)
  {
    if (user_options->benchmark == false)
    {
      if (user_options_extra->hc_workc)
      {
        char *arg = user_options_extra->hc_workv[0];

        if (hc_path_exist (arg) == false)
        {
          const int rc = mask_append (hashcat_ctx, arg, NULL);

          if (rc == -1) return -1;
        }
        else
        {
          mask_ctx->mask_from_file = true;

          for (int i = 0; i < user_options_extra->hc_workc; i++)
          {
            arg = user_options_extra->hc_workv[i];

            if (hc_path_is_file (arg) == true)
            {
              FILE *mask_fp = fopen (arg, "r");

              if (mask_fp == NULL)
              {
                event_log_error (hashcat_ctx, "%s: %s", arg, strerror (errno));

                return -1;
              }

              char *line_buf = (char *) hcmalloc (HCBUFSIZ_LARGE);

              while (!feof (mask_fp))
              {
                const size_t line_len = fgetl (mask_fp, line_buf);

                if (line_len == 0) continue;

                if (line_buf[0] == '#') continue;

                char *mask_buf = mask_ctx_parse_maskfile_find_mask (line_buf, line_len);

                char *prepend_buf = NULL;

                if (line_buf != mask_buf)
                {
                  // if we have custom charsets

                  prepend_buf = line_buf;

                  mask_buf[-1] = 0;
                }

                const int rc = mask_append (hashcat_ctx, mask_buf, prepend_buf);

                if (rc == -1)
                {
                  fclose (mask_fp);

                  return -1;
                }
              }

              hcfree (line_buf);

              fclose (mask_fp);
            }
            else
            {
              event_log_error (hashcat_ctx, "%s: unsupported file type.", arg);

              return -1;
            }
          }
        }
      }
      else
      {
        const char *mask = DEF_MASK;

        const int rc = mask_append (hashcat_ctx, mask, NULL);

        if (rc == -1) return -1;
      }
    }
    else
    {
      const char *mask = hashconfig_benchmark_mask (hashcat_ctx);

      const int rc = mask_append (hashcat_ctx, mask, NULL);

      if (rc == -1) return -1;
    }
  }
  else if (user_options->attack_mode == ATTACK_MODE_HYBRID1)
  {
    // display

    char *arg = user_options_extra->hc_workv[user_options_extra->hc_workc - 1];

    // mod

    if (hc_path_exist (arg) == false)
    {
      const int rc = mask_append (hashcat_ctx, arg, NULL);

      if (rc == -1) return -1;
    }
    else
    {
      if (hc_path_is_file (arg) == true)
      {
        mask_ctx->mask_from_file = true;

        FILE *mask_fp = fopen (arg, "r");

        if (mask_fp == NULL)
        {
          event_log_error (hashcat_ctx, "%s: %s", arg, strerror (errno));

          return -1;
        }

        char *line_buf = (char *) hcmalloc (HCBUFSIZ_LARGE);

        while (!feof (mask_fp))
        {
          const size_t line_len = fgetl (mask_fp, line_buf);

          if (line_len == 0) continue;

          if (line_buf[0] == '#') continue;

          char *mask_buf = mask_ctx_parse_maskfile_find_mask (line_buf, line_len);

          char *prepend_buf = NULL;

          if (line_buf != mask_buf)
          {
            // if we have custom charsets

            prepend_buf = line_buf;

            mask_buf[-1] = 0;
          }

          const int rc = mask_append (hashcat_ctx, mask_buf, prepend_buf);

          if (rc == -1)
          {
            fclose (mask_fp);

            return -1;
          }
        }

        hcfree (line_buf);

        fclose (mask_fp);
      }
      else
      {
        event_log_error (hashcat_ctx, "%s: unsupported file type.", arg);

        return -1;
      }
    }
  }
  else if (user_options->attack_mode == ATTACK_MODE_HYBRID2)
  {
    // display

    char *arg = user_options_extra->hc_workv[0];

    // mod

    if (hc_path_exist (arg) == false)
    {
      const int rc = mask_append (hashcat_ctx, arg, NULL);

      if (rc == -1) return -1;
    }
    else
    {
      if (hc_path_is_file (arg) == true)
      {
        mask_ctx->mask_from_file = true;

        FILE *mask_fp = fopen (arg, "r");

        if (mask_fp == NULL)
        {
          event_log_error (hashcat_ctx, "%s: %s", arg, strerror (errno));

          return -1;
        }

        char *line_buf = (char *) hcmalloc (HCBUFSIZ_LARGE);

        while (!feof (mask_fp))
        {
          const size_t line_len = fgetl (mask_fp, line_buf);

          if (line_len == 0) continue;

          if (line_buf[0] == '#') continue;

          char *mask_buf = mask_ctx_parse_maskfile_find_mask (line_buf, line_len);

          char *prepend_buf = NULL;

          if (line_buf != mask_buf)
          {
            // if we have custom charsets

            prepend_buf = line_buf;

            mask_buf[-1] = 0;
          }

          const int rc = mask_append (hashcat_ctx, mask_buf, prepend_buf);

          if (rc == -1)
          {
            fclose (mask_fp);

            return -1;
          }
        }

        hcfree (line_buf);

        fclose (mask_fp);
      }
      else
      {
        event_log_error (hashcat_ctx, "%s: unsupported file type.", arg);

        return -1;
      }
    }
  }

  if (mask_ctx->masks_cnt == 0)
  {
    event_log_error (hashcat_ctx, "Invalid mask.");

    return -1;
  }

  mask_ctx->mask = mask_ctx->masks[0];

  return 0;
}
Ejemplo n.º 4
0
int potfile_init (hashcat_ctx_t *hashcat_ctx)
{
  folder_config_t *folder_config = hashcat_ctx->folder_config;
  potfile_ctx_t   *potfile_ctx   = hashcat_ctx->potfile_ctx;
  user_options_t  *user_options  = hashcat_ctx->user_options;

  potfile_ctx->enabled = false;

  if (user_options->benchmark       == true) return 0;
  if (user_options->example_hashes  == true) return 0;
  if (user_options->keyspace        == true) return 0;
  if (user_options->opencl_info     == true) return 0;
  if (user_options->stdout_flag     == true) return 0;
  if (user_options->speed_only      == true) return 0;
  if (user_options->progress_only   == true) return 0;
  if (user_options->usage           == true) return 0;
  if (user_options->version         == true) return 0;
  if (user_options->potfile_disable == true) return 0;

  potfile_ctx->enabled = true;

  if (user_options->potfile_path == NULL)
  {
    potfile_ctx->fp       = NULL;

    hc_asprintf (&potfile_ctx->filename, "%s/hashcat.potfile", folder_config->profile_dir);
  }
  else
  {
    potfile_ctx->filename = hcstrdup (user_options->potfile_path);
    potfile_ctx->fp       = NULL;
  }

  // keep all hashes if --username was combined with --left or --show

  potfile_ctx->keep_all_hashes = false;

  if (user_options->username == true)
  {
    if ((user_options->show == true) || (user_options->left == true))
    {
      potfile_ctx->keep_all_hashes = true;
    }
  }

  // keep all hashes if -m 3000 was combined with --left or --show

  if (user_options->hash_mode == 3000)
  {
    if ((user_options->show == true) || (user_options->left == true))
    {
      potfile_ctx->keep_all_hashes = true;
    }
  }

  // starting from here, we should allocate some scratch buffer for later use

  u8 *out_buf = (u8 *) hcmalloc (HCBUFSIZ_LARGE);

  potfile_ctx->out_buf = out_buf;

  // we need two buffers in parallel

  u8 *tmp_buf = (u8 *) hcmalloc (HCBUFSIZ_LARGE);

  potfile_ctx->tmp_buf = tmp_buf;

  // old potfile detection

  if (user_options->potfile_path == NULL)
  {
    char *potfile_old;

    hc_asprintf (&potfile_old, "%s/hashcat.pot", folder_config->profile_dir);

    if (hc_path_exist (potfile_old) == true)
    {
      event_log_warning (hashcat_ctx, "Old potfile detected: %s", potfile_old);
      event_log_warning (hashcat_ctx, "New potfile is: %s ", potfile_ctx->filename);
      event_log_warning (hashcat_ctx, NULL);
    }

    hcfree (potfile_old);
  }

  return 0;
}
Ejemplo n.º 5
0
int potfile_remove_parse (hashcat_ctx_t *hashcat_ctx)
{
  const hashconfig_t   *hashconfig   = hashcat_ctx->hashconfig;
  const hashes_t       *hashes       = hashcat_ctx->hashes;
  const potfile_ctx_t  *potfile_ctx  = hashcat_ctx->potfile_ctx;

  if (potfile_ctx->enabled == false) return 0;

  // if no potfile exists yet we don't need to do anything here

  if (hc_path_exist (potfile_ctx->filename) == false) return 0;

  hash_t *hashes_buf = hashes->hashes_buf;
  u32     hashes_cnt = hashes->hashes_cnt;

  // no solution for these special hash types (for instane because they use hashfile in output etc)

  if  (hashconfig->hash_mode ==  5200)  return 0;
  if ((hashconfig->hash_mode >=  6200)
   && (hashconfig->hash_mode <=  6299)) return 0;
  if  (hashconfig->hash_mode ==  9000)  return 0;
  if ((hashconfig->hash_mode >= 13700)
   && (hashconfig->hash_mode <= 13799)) return 0;
  if  (hashconfig->hash_mode == 14600)  return 0;

  hash_t hash_buf;

  hash_buf.digest    = hcmalloc (hashconfig->dgst_size);
  hash_buf.salt      = NULL;
  hash_buf.esalt     = NULL;
  hash_buf.hook_salt = NULL;
  hash_buf.hash_info = NULL;
  hash_buf.cracked   = 0;

  if (hashconfig->is_salted == true)
  {
    hash_buf.salt = (salt_t *) hcmalloc (sizeof (salt_t));
  }

  if (hashconfig->esalt_size > 0)
  {
    hash_buf.esalt = hcmalloc (hashconfig->esalt_size);
  }

  if (hashconfig->hook_salt_size > 0)
  {
    hash_buf.hook_salt = hcmalloc (hashconfig->hook_salt_size);
  }

  // we only need this variable in a very specific situation:
  // whenever we use --username and --show together we want to keep all hashes sorted within a nice structure

  pot_tree_entry_t *all_hashes_tree  = NULL;
  pot_tree_entry_t *tree_entry_cache = NULL;
  pot_hash_node_t  *tree_nodes_cache = NULL;

  if (potfile_ctx->keep_all_hashes == true)
  {
    // we need *at most* one entry for every hash
    // (if there are no hashes with the same keys (hash + salt), a counter example would be: same hash but different user name)
    tree_entry_cache = (pot_tree_entry_t *) hccalloc (hashes_cnt, sizeof (pot_tree_entry_t));

    // we need *always exactly* one linked list for every hash
    tree_nodes_cache = (pot_hash_node_t  *) hccalloc (hashes_cnt, sizeof (pot_hash_node_t));

    for (u32 hash_pos = 0; hash_pos < hashes_cnt; hash_pos++)
    {
      // initialize the linked list node:
      // we always need to create a new one and add it, because we want to keep and later update all hashes:

      pot_hash_node_t *new_node = &tree_nodes_cache[hash_pos];

      new_node->hash_buf = &hashes_buf[hash_pos];
      new_node->next     = NULL;

      // initialize the entry:

      pot_tree_entry_t *new_entry = &tree_entry_cache[hash_pos];

      // note: the "key" (hash + salt) is indirectly accessible via the first nodes "hash_buf"

      new_entry->nodes      = new_node;
      // the hashconfig is needed here because we need to be able to check within the sort function if we also need
      // to sort by salt and we also need to have the correct order of dgst_pos0...dgst_pos3:
      new_entry->hashconfig = (hashconfig_t *) hashconfig; // "const hashconfig_t" gives a warning


      // the following function searches if the "key" is already present and if not inserts the new entry:

      void **found = tsearch (new_entry, (void **) &all_hashes_tree, sort_pot_tree_by_hash);

      pot_tree_entry_t *found_entry = (pot_tree_entry_t *) *found;

      // we now need to check these cases; tsearch () could return:
      // 1. NULL : if we have a memory allocation problem (not enough memory for the tree structure)
      // 2. found_entry == new_entry: if we successfully insert a new key (which was not present yet)
      // 3. found_entry != new_entry: if the key was already present

      // case 1: memory allocation error

      if (found_entry == NULL)
      {
        fprintf (stderr, "Error while allocating memory for the potfile search: %s\n", MSG_ENOMEM);

        return -1;
      }

      // case 2: this means it was a new insert (and the insert was successful)

      if (found_entry == new_entry)
      {
        // no updates to the linked list required (since it is the first one!)
      }
      // case 3: if we have found an already existing entry
      else
      {
        new_node->next = found_entry->nodes;
      }

      // we always insert the new node at the very beginning
      // (or in other words: the head of the linked list always points to *this* new inserted node)

      found_entry->nodes = new_node;
    }
  }


  // special case for a split hash

  if (hashconfig->hash_mode == 3000)
  {
    int parser_status = hashconfig->parse_func ((u8 *) LM_ZERO_HASH, 16, &hash_buf, hashconfig);

    if (parser_status == PARSER_OK)
    {
      if (potfile_ctx->keep_all_hashes == true)
      {
        potfile_update_hashes (hashcat_ctx, &hash_buf, NULL, 0, all_hashes_tree);
      }
      else
      {
        hash_t *found = (hash_t *) hc_bsearch_r (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash_no_salt, (void *) hashconfig);

        potfile_update_hash (hashcat_ctx, found, NULL, 0);
      }
    }
  }

  const int rc = potfile_read_open (hashcat_ctx);

  if (rc == -1) return -1;

  char *line_buf = (char *) hcmalloc (HCBUFSIZ_LARGE);

  while (!feof (potfile_ctx->fp))
  {
    int line_len = fgetl (potfile_ctx->fp, line_buf);

    if (line_len == 0) continue;

    char *last_separator = strrchr (line_buf, hashconfig->separator);

    if (last_separator == NULL) continue; // ??

    char *line_pw_buf = last_separator + 1;

    int line_pw_len = line_buf + line_len - line_pw_buf;

    char *line_hash_buf = line_buf;

    int line_hash_len = last_separator - line_buf;

    line_hash_buf[line_hash_len] = 0;

    if (line_hash_len == 0) continue;

    if (hashconfig->is_salted == true)
    {
      memset (hash_buf.salt, 0, sizeof (salt_t));
    }

    if (hashconfig->esalt_size > 0)
    {
      memset (hash_buf.esalt, 0, hashconfig->esalt_size);
    }

    if (hashconfig->hook_salt_size > 0)
    {
      memset (hash_buf.hook_salt, 0, hashconfig->hook_salt_size);
    }

    hash_t *found = NULL;

    if (hashconfig->hash_mode == 6800)
    {
      if (line_hash_len < 256) // 64 = 64 * u32 in salt_buf[]
      {
        // manipulate salt_buf
        memcpy (hash_buf.salt->salt_buf, line_hash_buf, line_hash_len);

        hash_buf.salt->salt_len = line_hash_len;

        found = (hash_t *) bsearch (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash_t_salt);
      }
    }
    else if ((hashconfig->hash_mode == 2500) || (hashconfig->hash_mode == 2501))
    {
      // here we have in line_hash_buf: hash:macap:macsta:essid:password

      char *sep_pos = strrchr (line_hash_buf, ':');

      if (sep_pos == NULL) continue;

      sep_pos[0] = 0;

      char *hash_pos = line_hash_buf;

      const size_t hash_len = strlen (hash_pos);

      if (hash_len != 32 + 1 + 12 + 1 + 12) continue;

      char *essid_pos = sep_pos + 1;

      int essid_len = (int) strlen (essid_pos);

      if (is_hexify ((const u8 *) essid_pos, (const int) essid_len) == true)
      {
        essid_len = exec_unhexify ((const u8 *) essid_pos, essid_len, (u8 *) essid_pos, essid_len);
      }

      if (essid_len > 32) continue;

      if (hashconfig->is_salted == true)
      {
        // this should be always true, but we need it to make scan-build happy

        memcpy (hash_buf.salt->salt_buf, essid_pos, essid_len);

        hash_buf.salt->salt_len  = essid_len;
        hash_buf.salt->salt_iter = ROUNDS_WPA - 1;

        u32 hash[4];

        hash[0] = hex_to_u32 ((const u8 *) &hash_pos[ 0]);
        hash[1] = hex_to_u32 ((const u8 *) &hash_pos[ 8]);
        hash[2] = hex_to_u32 ((const u8 *) &hash_pos[16]);
        hash[3] = hex_to_u32 ((const u8 *) &hash_pos[24]);

        hash[0] = byte_swap_32 (hash[0]);
        hash[1] = byte_swap_32 (hash[1]);
        hash[2] = byte_swap_32 (hash[2]);
        hash[3] = byte_swap_32 (hash[3]);

        u32 *digest = (u32 *) hash_buf.digest;

        digest[0] = hash[0];
        digest[1] = hash[1];
        digest[2] = hash[2];
        digest[3] = hash[3];
      }

      found = (hash_t *) hc_bsearch_r (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash, (void *) hashconfig);
    }
    else
    {
      int parser_status = hashconfig->parse_func ((u8 *) line_hash_buf, line_hash_len, &hash_buf, hashconfig);

      if (parser_status != PARSER_OK) continue;

      if (potfile_ctx->keep_all_hashes == true)
      {
        potfile_update_hashes (hashcat_ctx, &hash_buf, line_pw_buf, line_pw_len, all_hashes_tree);

        continue;
      }

      found = (hash_t *) hc_bsearch_r (&hash_buf, hashes_buf, hashes_cnt, sizeof (hash_t), sort_by_hash, (void *) hashconfig);
    }

    potfile_update_hash (hashcat_ctx, found, line_pw_buf, line_pw_len);
  }

  hcfree (line_buf);

  potfile_read_close (hashcat_ctx);


  if (potfile_ctx->keep_all_hashes == true)
  {
    pot_tree_destroy (all_hashes_tree); // this could be slow (should we just skip it?)

    hcfree (tree_nodes_cache);
    hcfree (tree_entry_cache);
  }

  if (hashconfig->esalt_size > 0)
  {
    hcfree (hash_buf.esalt);
  }

  if (hashconfig->hook_salt_size > 0)
  {
    hcfree (hash_buf.hook_salt);
  }

  if (hashconfig->is_salted == true)
  {
    hcfree (hash_buf.salt);
  }

  hcfree (hash_buf.digest);

  return 0;
}
Ejemplo n.º 6
0
static int outfile_remove (hashcat_ctx_t *hashcat_ctx)
{
  // some hash-dependent constants

  hashconfig_t   *hashconfig   = hashcat_ctx->hashconfig;
  hashes_t       *hashes       = hashcat_ctx->hashes;
  outcheck_ctx_t *outcheck_ctx = hashcat_ctx->outcheck_ctx;
  status_ctx_t   *status_ctx   = hashcat_ctx->status_ctx;
  user_options_t *user_options = hashcat_ctx->user_options;

  u32  dgst_size      = hashconfig->dgst_size;
  bool is_salted      = hashconfig->is_salted;
  u32  esalt_size     = hashconfig->esalt_size;
  u32  hook_salt_size = hashconfig->hook_salt_size;
  u32  hash_mode      = hashconfig->hash_mode;
  char separator      = hashconfig->separator;

  char *root_directory      = outcheck_ctx->root_directory;
  u32   outfile_check_timer = user_options->outfile_check_timer;

  // buffers
  hash_t hash_buf = { 0, 0, 0, 0, 0, 0, NULL, 0 };

  hash_buf.digest = hcmalloc (dgst_size);

  if (is_salted == true)  hash_buf.salt      = (salt_t *) hcmalloc (sizeof (salt_t));
  if (esalt_size > 0)     hash_buf.esalt     = hcmalloc (esalt_size);
  if (hook_salt_size > 0) hash_buf.hook_salt = hcmalloc (hook_salt_size);

  u32 digest_buf[64] = { 0 };

  outfile_data_t *out_info = NULL;

  char **out_files = NULL;

  time_t folder_mtime = 0;

  int out_cnt = 0;

  u32 check_left = outfile_check_timer; // or 1 if we want to check it at startup

  while (status_ctx->shutdown_inner == false)
  {
    sleep (1);

    if (status_ctx->devices_status != STATUS_RUNNING) continue;

    check_left--;

    if (check_left == 0)
    {
      if (hc_path_exist (root_directory) == true)
      {
        const bool is_dir = hc_path_is_directory (root_directory);

        if (is_dir == true)
        {
          struct stat outfile_check_stat;

          if (stat (root_directory, &outfile_check_stat) == -1)
          {
            event_log_error (hashcat_ctx, "%s: %s", root_directory, strerror (errno));

            hcfree (out_files);
            hcfree (out_info);

            return -1;
          }

          if (outfile_check_stat.st_mtime > folder_mtime)
          {
            char **out_files_new = scan_directory (root_directory);

            int out_cnt_new = count_dictionaries (out_files_new);

            outfile_data_t *out_info_new = NULL;

            if (out_cnt_new > 0)
            {
              out_info_new = (outfile_data_t *) hccalloc (out_cnt_new, sizeof (outfile_data_t));

              for (int i = 0; i < out_cnt_new; i++)
              {
                out_info_new[i].file_name = out_files_new[i];

                // check if there are files that we have seen/checked before (and not changed)

                for (int j = 0; j < out_cnt; j++)
                {
                  if (strcmp (out_info[j].file_name, out_info_new[i].file_name) == 0)
                  {
                    struct stat outfile_stat;

                    if (stat (out_info_new[i].file_name, &outfile_stat) == 0)
                    {
                      if (outfile_stat.st_ctime == out_info[j].ctime)
                      {
                        out_info_new[i].ctime = out_info[j].ctime;
                        out_info_new[i].seek  = out_info[j].seek;
                      }
                    }
                  }
                }
              }
            }

            hcfree (out_info);
            hcfree (out_files);

            out_files = out_files_new;
            out_cnt   = out_cnt_new;
            out_info  = out_info_new;

            folder_mtime = outfile_check_stat.st_mtime;
          }

          for (int j = 0; j < out_cnt; j++)
          {
            FILE *fp = fopen (out_info[j].file_name, "rb");

            if (fp != NULL)
            {
              //hc_thread_mutex_lock (status_ctx->mux_display);

              struct stat outfile_stat;

              if (fstat (fileno (fp), &outfile_stat))
              {
                fclose (fp);

                continue;
              }

              if (outfile_stat.st_ctime > out_info[j].ctime)
              {
                out_info[j].ctime = outfile_stat.st_ctime;
                out_info[j].seek  = 0;
              }

              fseeko (fp, out_info[j].seek, SEEK_SET);

              char *line_buf = (char *) hcmalloc (HCBUFSIZ_LARGE);

              while (!feof (fp))
              {
                char *ptr = fgets (line_buf, HCBUFSIZ_LARGE - 1, fp);

                if (ptr == NULL) break;

                size_t line_len = strlen (line_buf);

                if (line_len == 0) continue;

                size_t iter = 1;

                for (size_t i = line_len - 1; i && iter; i--, line_len--)
                {
                  if (line_buf[i] != separator) continue;

                  iter--;

                  int parser_status = PARSER_OK;

                  if ((hash_mode != 2500) && (hash_mode != 2501) && (hash_mode != 6800))
                  {
                    parser_status = hashconfig->parse_func ((u8 *) line_buf, line_len - 1, &hash_buf, hashconfig);
                  }

                  u32 found = 0;

                  if (parser_status == PARSER_OK)
                  {
                    for (u32 salt_pos = 0; (found == 0) && (salt_pos < hashes->salts_cnt); salt_pos++)
                    {
                      if (hashes->salts_shown[salt_pos] == 1) continue;

                      salt_t *salt_buf = &hashes->salts_buf[salt_pos];

                      for (u32 digest_pos = 0; (found == 0) && (digest_pos < salt_buf->digests_cnt); digest_pos++)
                      {
                        u32 idx = salt_buf->digests_offset + digest_pos;

                        if (hashes->digests_shown[idx] == 1) continue;

                        u32 cracked = 0;

                        if (hash_mode == 6800)
                        {
                          if (i == salt_buf->salt_len)
                          {
                            cracked = (memcmp (line_buf, salt_buf->salt_buf, salt_buf->salt_len) == 0);
                          }
                        }
                        else if ((hash_mode == 2500) || (hash_mode == 2501))
                        {
                          // this comparison is a bit inaccurate as we compare only ESSID
                          // call it a bug, but it's good enough for a special case used in a special case
                          // in this case all essid will be marked as cracked that match the essid

                          if (i == salt_buf->salt_len)
                          {
                            cracked = (memcmp (line_buf, salt_buf->salt_buf, salt_buf->salt_len) == 0);
                          }
                        }
                        else
                        {
                          char *digests_buf_ptr = (char *) hashes->digests_buf;

                          memcpy (digest_buf, digests_buf_ptr + (hashes->salts_buf[salt_pos].digests_offset * dgst_size) + (digest_pos * dgst_size), dgst_size);

                          cracked = (sort_by_digest_p0p1 (digest_buf, hash_buf.digest, hashconfig) == 0);
                        }

                        if (cracked == 1)
                        {
                          found = 1;

                          hashes->digests_shown[idx] = 1;

                          hashes->digests_done++;

                          salt_buf->digests_done++;

                          if (salt_buf->digests_done == salt_buf->digests_cnt)
                          {
                            hashes->salts_shown[salt_pos] = 1;

                            hashes->salts_done++;

                            if (hashes->salts_done == hashes->salts_cnt) mycracked (hashcat_ctx);
                          }
                        }
                      }

                      if (status_ctx->devices_status == STATUS_CRACKED) break;
                    }
                  }

                  if (found) break;

                  if (status_ctx->devices_status == STATUS_CRACKED) break;
                }

                if (status_ctx->devices_status == STATUS_CRACKED) break;
              }

              hcfree (line_buf);

              out_info[j].seek = ftello (fp);

              //hc_thread_mutex_unlock (status_ctx->mux_display);

              fclose (fp);
            }
          }
        }
      }

      check_left = outfile_check_timer;
    }
  }

  hcfree (hash_buf.esalt);
  hcfree (hash_buf.hook_salt);

  hcfree (hash_buf.salt);

  hcfree (hash_buf.digest);

  hcfree (out_info);

  hcfree (out_files);

  return 0;
}