save_hash() always works with a file, therefore no branch required
[hashcat.git] / src / hashcat.c
index 20305b6..8e66149 100644 (file)
@@ -1,4 +1,4 @@
-/**
+ /**
  * Authors.....: Jens Steube <jens.steube@gmail.com>
  *               Gabriele Gristina <matrix@hashcat.net>
  *               magnum <john.magnum@hushmail.com>
@@ -33,6 +33,7 @@ double TARGET_MS_PROFILE[4]     = { 2, 12, 96, 480 };
 #define MARKOV_DISABLE          0
 #define MARKOV_CLASSIC          0
 #define BENCHMARK               0
+#define STDOUT_FLAG             0
 #define RESTORE                 0
 #define RESTORE_TIMER           60
 #define RESTORE_DISABLE         0
@@ -150,6 +151,8 @@ double TARGET_MS_PROFILE[4]     = { 2, 12, 96, 480 };
 
 #define NUM_DEFAULT_BENCHMARK_ALGORITHMS 143
 
+#define NVIDIA_100PERCENTCPU_WORKAROUND 100
+
 #define global_free(attr)       \
 {                               \
   myfree ((void *) data.attr);  \
@@ -164,6 +167,12 @@ double TARGET_MS_PROFILE[4]     = { 2, 12, 96, 480 };
   attr = NULL;            \
 }
 
+#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#define HC_API_CALL __stdcall
+#else
+#define HC_API_CALL
+#endif
+
 static uint default_benchmark_algorithms[NUM_DEFAULT_BENCHMARK_ALGORITHMS] =
 {
   900,
@@ -380,6 +389,7 @@ const char *USAGE_BIG[] =
   "     --outfile-autohex-disable |      | Disable the use of $HEX[] in output plains           |",
   "     --outfile-check-timer     | Num  | Sets seconds between outfile checks to X             | --outfile-check=30",
   " -p, --separator               | Char | Separator char for hashlists and outfile             | -p :",
+  "     --stdout                  |      | Do not crack a hash, instead print candidates only   |",
   "     --show                    |      | Show cracked passwords only                          |",
   "     --left                    |      | Show un-cracked passwords only                       |",
   "     --username                |      | Enable ignoring of usernames in hashfile             |",
@@ -570,6 +580,7 @@ const char *USAGE_BIG[] =
   "     22 | Juniper Netscreen/SSG (ScreenOS)                 | Operating-Systems",
   "    501 | Juniper IVE                                      | Operating-Systems",
   "   5800 | Android PIN                                      | Operating-Systems",
+  "  13800 | Windows 8+ phone PIN/Password                    | Operating-Systems",
   "   8100 | Citrix Netscaler                                 | Operating-Systems",
   "   8500 | RACF                                             | Operating-Systems",
   "   7200 | GRUB 2                                           | Operating-Systems",
@@ -1531,6 +1542,12 @@ void status_display ()
   }
 
   #ifdef HAVE_HWMON
+
+  if (data.devices_status == STATUS_EXHAUSTED)  return;
+  if (data.devices_status == STATUS_CRACKED)    return;
+  if (data.devices_status == STATUS_ABORTED)    return;
+  if (data.devices_status == STATUS_QUIT)       return;
+
   if (data.gpu_temp_disable == 0)
   {
     hc_thread_mutex_lock (mux_adl);
@@ -1614,6 +1631,7 @@ void status_display ()
 
     hc_thread_mutex_unlock (mux_adl);
   }
+
   #endif // HAVE_HWMON
 }
 
@@ -2297,6 +2315,175 @@ static void check_cracked (hc_device_param_t *device_param, const uint salt_pos)
   }
 }
 
+static void process_stdout (hc_device_param_t *device_param, const uint pws_cnt)
+{
+  char out_buf[HCBUFSIZ] = { 0 };
+
+  uint plain_buf[16] = { 0 };
+
+  u8 *plain_ptr = (u8 *) plain_buf;
+
+  uint plain_len = 0;
+
+  const uint il_cnt = device_param->kernel_params_buf32[27]; // ugly, i know
+
+  if (data.attack_mode == ATTACK_MODE_STRAIGHT)
+  {
+    pw_t pw;
+
+    for (uint gidvid = 0; gidvid < pws_cnt; gidvid++)
+    {
+      gidd_to_pw_t (device_param, gidvid, &pw);
+
+      const uint pos = device_param->innerloop_pos;
+
+      for (uint il_pos = 0; il_pos < il_cnt; il_pos++)
+      {
+        for (int i = 0; i < 8; i++)
+        {
+          plain_buf[i] = pw.i[i];
+        }
+
+        plain_len = pw.pw_len;
+
+        plain_len = apply_rules (data.kernel_rules_buf[pos + il_pos].cmds, &plain_buf[0], &plain_buf[4], plain_len);
+
+        if (plain_len > data.pw_max) plain_len = data.pw_max;
+
+        format_output (stdout, out_buf, plain_ptr, plain_len, 0, NULL, 0);
+      }
+    }
+  }
+  else if (data.attack_mode == ATTACK_MODE_COMBI)
+  {
+    pw_t pw;
+
+    for (uint gidvid = 0; gidvid < pws_cnt; gidvid++)
+    {
+      gidd_to_pw_t (device_param, gidvid, &pw);
+
+      for (uint il_pos = 0; il_pos < il_cnt; il_pos++)
+      {
+        for (int i = 0; i < 8; i++)
+        {
+          plain_buf[i] = pw.i[i];
+        }
+
+        plain_len = pw.pw_len;
+
+        char *comb_buf = (char *) device_param->combs_buf[il_pos].i;
+        uint  comb_len =          device_param->combs_buf[il_pos].pw_len;
+
+        if (data.combs_mode == COMBINATOR_MODE_BASE_LEFT)
+        {
+          memcpy (plain_ptr + plain_len, comb_buf, comb_len);
+        }
+        else
+        {
+          memmove (plain_ptr + comb_len, plain_ptr, plain_len);
+
+          memcpy (plain_ptr, comb_buf, comb_len);
+        }
+
+        plain_len += comb_len;
+
+        if (data.pw_max != PW_DICTMAX1)
+        {
+          if (plain_len > data.pw_max) plain_len = data.pw_max;
+        }
+
+        format_output (stdout, out_buf, plain_ptr, plain_len, 0, NULL, 0);
+      }
+    }
+  }
+  else if (data.attack_mode == ATTACK_MODE_BF)
+  {
+    for (uint gidvid = 0; gidvid < pws_cnt; gidvid++)
+    {
+      for (uint il_pos = 0; il_pos < il_cnt; il_pos++)
+      {
+        u64 l_off = device_param->kernel_params_mp_l_buf64[3] + gidvid;
+        u64 r_off = device_param->kernel_params_mp_r_buf64[3] + il_pos;
+
+        uint l_start = device_param->kernel_params_mp_l_buf32[5];
+        uint r_start = device_param->kernel_params_mp_r_buf32[5];
+
+        uint l_stop = device_param->kernel_params_mp_l_buf32[4];
+        uint r_stop = device_param->kernel_params_mp_r_buf32[4];
+
+        sp_exec (l_off, (char *) plain_ptr + l_start, data.root_css_buf, data.markov_css_buf, l_start, l_start + l_stop);
+        sp_exec (r_off, (char *) plain_ptr + r_start, data.root_css_buf, data.markov_css_buf, r_start, r_start + r_stop);
+
+        plain_len = data.css_cnt;
+
+        format_output (stdout, out_buf, plain_ptr, plain_len, 0, NULL, 0);
+      }
+    }
+  }
+  else if (data.attack_mode == ATTACK_MODE_HYBRID1)
+  {
+    pw_t pw;
+
+    for (uint gidvid = 0; gidvid < pws_cnt; gidvid++)
+    {
+      gidd_to_pw_t (device_param, gidvid, &pw);
+
+      for (uint il_pos = 0; il_pos < il_cnt; il_pos++)
+      {
+        for (int i = 0; i < 8; i++)
+        {
+          plain_buf[i] = pw.i[i];
+        }
+
+        plain_len = pw.pw_len;
+
+        u64 off = device_param->kernel_params_mp_buf64[3] + il_pos;
+
+        uint start = 0;
+        uint stop  = device_param->kernel_params_mp_buf32[4];
+
+        sp_exec (off, (char *) plain_ptr + plain_len, data.root_css_buf, data.markov_css_buf, start, start + stop);
+
+        plain_len += start + stop;
+
+        format_output (stdout, out_buf, plain_ptr, plain_len, 0, NULL, 0);
+      }
+    }
+  }
+  else if (data.attack_mode == ATTACK_MODE_HYBRID2)
+  {
+    pw_t pw;
+
+    for (uint gidvid = 0; gidvid < pws_cnt; gidvid++)
+    {
+      gidd_to_pw_t (device_param, gidvid, &pw);
+
+      for (uint il_pos = 0; il_pos < il_cnt; il_pos++)
+      {
+        for (int i = 0; i < 8; i++)
+        {
+          plain_buf[i] = pw.i[i];
+        }
+
+        plain_len = pw.pw_len;
+
+        u64 off = device_param->kernel_params_mp_buf64[3] + il_pos;
+
+        uint start = 0;
+        uint stop  = device_param->kernel_params_mp_buf32[4];
+
+        memmove (plain_ptr + stop, plain_ptr, plain_len);
+
+        sp_exec (off, (char *) plain_ptr, data.root_css_buf, data.markov_css_buf, start, start + stop);
+
+        plain_len += start + stop;
+
+        format_output (stdout, out_buf, plain_ptr, plain_len, 0, NULL, 0);
+      }
+    }
+  }
+}
+
 static void save_hash ()
 {
   char *hashfile = data.hashfile;
@@ -2334,8 +2521,6 @@ static void save_hash ()
 
       if (data.hash_mode != 2500)
       {
-        char out_buf[HCBUFSIZ] = { 0 };
-
         if (data.username == 1)
         {
           user_t *user = data.hash_info[idx]->user;
@@ -2347,11 +2532,15 @@ static void save_hash ()
           fputc (separator, fp);
         }
 
+        char out_buf[HCBUFSIZ]; // scratch buffer
+
+        out_buf[0] = 0;
+
         ascii_digest (out_buf, salt_pos, digest_pos);
 
         fputs (out_buf, fp);
 
-        log_out (fp, "");
+        fputc ('\n', fp);
       }
       else
       {
@@ -2389,43 +2578,7 @@ static void save_hash ()
   unlink (old_hashfile);
 }
 
-static float find_kernel_power_div (const u64 total_left, const uint kernel_power_all)
-{
-  // function called only in case kernel_power_all > words_left
-
-  float kernel_power_div = (float) (total_left) / kernel_power_all;
-
-  kernel_power_div += kernel_power_div / 100;
-
-  u32 kernel_power_new = (u32) (kernel_power_all * kernel_power_div);
-
-  while (kernel_power_new < total_left)
-  {
-    kernel_power_div += kernel_power_div / 100;
-
-    kernel_power_new = (u32) (kernel_power_all * kernel_power_div);
-  }
-
-  if (data.quiet == 0)
-  {
-    clear_prompt ();
-
-    //log_info ("");
-
-    log_info ("INFO: approaching final keyspace, workload adjusted");
-    log_info ("");
-
-    fprintf (stdout, "%s", PROMPT);
-
-    fflush (stdout);
-  }
-
-  //if ((kernel_power_all * kernel_power_div) < 8) return 1;
-
-  return kernel_power_div;
-}
-
-static void run_kernel (const uint kern_run, hc_device_param_t *device_param, const uint num, const uint event_update)
+static void run_kernel (const uint kern_run, hc_device_param_t *device_param, const uint num, const uint event_update, const uint iteration)
 {
   uint num_elements = num;
 
@@ -2488,21 +2641,47 @@ static void run_kernel (const uint kern_run, hc_device_param_t *device_param, co
 
   hc_clFlush (data.ocl, device_param->command_queue);
 
+  if (data.devices_status == STATUS_RUNNING)
+  {
+    if (iteration < EXPECTED_ITERATIONS)
+    {
+      switch (kern_run)
+      {
+        case KERN_RUN_1: if (device_param->exec_us_prev1[iteration]) usleep (device_param->exec_us_prev1[iteration]); break;
+        case KERN_RUN_2: if (device_param->exec_us_prev2[iteration]) usleep (device_param->exec_us_prev2[iteration]); break;
+        case KERN_RUN_3: if (device_param->exec_us_prev3[iteration]) usleep (device_param->exec_us_prev3[iteration]); break;
+      }
+    }
+  }
+
   hc_clWaitForEvents (data.ocl, 1, &event);
 
-  if (event_update)
-  {
-    cl_ulong time_start;
-    cl_ulong time_end;
+  cl_ulong time_start;
+  cl_ulong time_end;
 
-    hc_clGetEventProfilingInfo (data.ocl, event, CL_PROFILING_COMMAND_START, sizeof (time_start), &time_start, NULL);
-    hc_clGetEventProfilingInfo (data.ocl, event, CL_PROFILING_COMMAND_END,   sizeof (time_end),   &time_end,   NULL);
+  hc_clGetEventProfilingInfo (data.ocl, event, CL_PROFILING_COMMAND_START, sizeof (time_start), &time_start, NULL);
+  hc_clGetEventProfilingInfo (data.ocl, event, CL_PROFILING_COMMAND_END,   sizeof (time_end),   &time_end,   NULL);
 
-    const double exec_time = (double) (time_end - time_start) / 1000000.0;
+  const double exec_us = (double) (time_end - time_start) / 1000;
+
+  if (data.devices_status == STATUS_RUNNING)
+  {
+    if (iteration < EXPECTED_ITERATIONS)
+    {
+      switch (kern_run)
+      {
+        case KERN_RUN_1: device_param->exec_us_prev1[iteration] = exec_us; break;
+        case KERN_RUN_2: device_param->exec_us_prev2[iteration] = exec_us; break;
+        case KERN_RUN_3: device_param->exec_us_prev3[iteration] = exec_us; break;
+      }
+    }
+  }
 
+  if (event_update)
+  {
     uint exec_pos = device_param->exec_pos;
 
-    device_param->exec_ms[exec_pos] = exec_time;
+    device_param->exec_ms[exec_pos] = exec_us / 1000;
 
     exec_pos++;
 
@@ -2715,8 +2894,15 @@ static void run_kernel_bzero (hc_device_param_t *device_param, cl_mem buf, const
   */
 }
 
-static void choose_kernel (hc_device_param_t *device_param, const uint attack_exec, const uint attack_mode, const uint opts_type, const salt_t *salt_buf, const uint highest_pw_len, const uint pws_cnt)
+static void choose_kernel (hc_device_param_t *device_param, const uint attack_exec, const uint attack_mode, const uint opts_type, const salt_t *salt_buf, const uint highest_pw_len, const uint pws_cnt, const uint fast_iteration)
 {
+  if (data.hash_mode == 2000)
+  {
+    process_stdout (device_param, pws_cnt);
+
+    return;
+  }
+
   if (attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
   {
     if (attack_mode == ATTACK_MODE_BF)
@@ -2735,33 +2921,39 @@ static void choose_kernel (hc_device_param_t *device_param, const uint attack_ex
 
     if (highest_pw_len < 16)
     {
-      run_kernel (KERN_RUN_1, device_param, pws_cnt, true);
+      run_kernel (KERN_RUN_1, device_param, pws_cnt, true, fast_iteration);
     }
     else if (highest_pw_len < 32)
     {
-      run_kernel (KERN_RUN_2, device_param, pws_cnt, true);
+      run_kernel (KERN_RUN_2, device_param, pws_cnt, true, fast_iteration);
     }
     else
     {
-      run_kernel (KERN_RUN_3, device_param, pws_cnt, true);
+      run_kernel (KERN_RUN_3, device_param, pws_cnt, true, fast_iteration);
     }
   }
   else
   {
     run_kernel_amp (device_param, pws_cnt);
 
-    run_kernel (KERN_RUN_1, device_param, pws_cnt, false);
+    run_kernel (KERN_RUN_1, device_param, pws_cnt, false, 0);
 
     if (opts_type & OPTS_TYPE_HOOK12)
     {
-      run_kernel (KERN_RUN_12, device_param, pws_cnt, false);
+      run_kernel (KERN_RUN_12, device_param, pws_cnt, false, 0);
+
+      hc_clEnqueueReadBuffer (data.ocl, device_param->command_queue, device_param->d_hooks, CL_TRUE, 0, device_param->size_hooks, device_param->hooks_buf, 0, NULL, NULL);
+
+      // do something with data
+
+      hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_hooks, CL_TRUE, 0, device_param->size_hooks, device_param->hooks_buf, 0, NULL, NULL);
     }
 
     uint iter = salt_buf->salt_iter;
 
     uint loop_step = device_param->kernel_loops;
 
-    for (uint loop_pos = 0; loop_pos < iter; loop_pos += loop_step)
+    for (uint loop_pos = 0, slow_iteration = 0; loop_pos < iter; loop_pos += loop_step, slow_iteration++)
     {
       uint loop_left = iter - loop_pos;
 
@@ -2770,7 +2962,7 @@ static void choose_kernel (hc_device_param_t *device_param, const uint attack_ex
       device_param->kernel_params_buf32[25] = loop_pos;
       device_param->kernel_params_buf32[26] = loop_left;
 
-      run_kernel (KERN_RUN_2, device_param, pws_cnt, true);
+      run_kernel (KERN_RUN_2, device_param, pws_cnt, true, slow_iteration);
 
       if (data.devices_status == STATUS_CRACKED) break;
       if (data.devices_status == STATUS_ABORTED) break;
@@ -2802,7 +2994,7 @@ static void choose_kernel (hc_device_param_t *device_param, const uint attack_ex
 
     if (opts_type & OPTS_TYPE_HOOK23)
     {
-      run_kernel (KERN_RUN_23, device_param, pws_cnt, false);
+      run_kernel (KERN_RUN_23, device_param, pws_cnt, false, 0);
 
       hc_clEnqueueReadBuffer (data.ocl, device_param->command_queue, device_param->d_hooks, CL_TRUE, 0, device_param->size_hooks, device_param->hooks_buf, 0, NULL, NULL);
 
@@ -2811,7 +3003,7 @@ static void choose_kernel (hc_device_param_t *device_param, const uint attack_ex
       hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_hooks, CL_TRUE, 0, device_param->size_hooks, device_param->hooks_buf, 0, NULL, NULL);
     }
 
-    run_kernel (KERN_RUN_3, device_param, pws_cnt, false);
+    run_kernel (KERN_RUN_3, device_param, pws_cnt, false, 0);
   }
 }
 
@@ -2913,11 +3105,11 @@ static double try_run (hc_device_param_t *device_param, const u32 kernel_accel,
 
   if (data.attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
   {
-    run_kernel (KERN_RUN_1, device_param, kernel_power_try, true);
+    run_kernel (KERN_RUN_1, device_param, kernel_power_try, true, 0);
   }
   else
   {
-    run_kernel (KERN_RUN_2, device_param, kernel_power_try, true);
+    run_kernel (KERN_RUN_2, device_param, kernel_power_try, true, 0);
   }
 
   const double exec_ms_prev = get_avg_exec_time (device_param, 1);
@@ -2944,10 +3136,13 @@ static void autotune (hc_device_param_t *device_param)
 
   if ((kernel_loops_min == kernel_loops_max) && (kernel_accel_min == kernel_accel_max))
   {
-    try_run (device_param, kernel_accel, kernel_loops);
-    try_run (device_param, kernel_accel, kernel_loops);
-    try_run (device_param, kernel_accel, kernel_loops);
-    try_run (device_param, kernel_accel, kernel_loops);
+    if (data.hash_mode != 2000)
+    {
+      try_run (device_param, kernel_accel, kernel_loops);
+      try_run (device_param, kernel_accel, kernel_loops);
+      try_run (device_param, kernel_accel, kernel_loops);
+      try_run (device_param, kernel_accel, kernel_loops);
+    }
 
     device_param->kernel_accel = kernel_accel;
     device_param->kernel_loops = kernel_loops;
@@ -3133,6 +3328,10 @@ static void autotune (hc_device_param_t *device_param)
 
   memset (device_param->exec_ms, 0, EXEC_CACHE * sizeof (double));
 
+  memset (device_param->exec_us_prev1, 0, EXPECTED_ITERATIONS * sizeof (double));
+  memset (device_param->exec_us_prev2, 0, EXPECTED_ITERATIONS * sizeof (double));
+  memset (device_param->exec_us_prev3, 0, EXPECTED_ITERATIONS * sizeof (double));
+
   // store
 
   device_param->kernel_accel = kernel_accel;
@@ -3250,9 +3449,16 @@ static void run_cracker (hc_device_param_t *device_param, const uint pws_cnt)
       if (data.devices_status == STATUS_QUIT)    break;
       if (data.devices_status == STATUS_BYPASS)  break;
 
+      uint fast_iteration = 0;
+
       uint innerloop_left = innerloop_cnt - innerloop_pos;
 
-      if (innerloop_left > innerloop_step) innerloop_left = innerloop_step;
+      if (innerloop_left > innerloop_step)
+      {
+        innerloop_left = innerloop_step;
+
+        fast_iteration = 1;
+      }
 
       device_param->innerloop_pos  = innerloop_pos;
       device_param->innerloop_left = innerloop_left;
@@ -3410,7 +3616,7 @@ static void run_cracker (hc_device_param_t *device_param, const uint pws_cnt)
         hc_timer_set (&device_param->timer_speed);
       }
 
-      choose_kernel (device_param, data.attack_exec, data.attack_mode, data.opts_type, salt_buf, highest_pw_len, pws_cnt);
+      choose_kernel (device_param, data.attack_exec, data.attack_mode, data.opts_type, salt_buf, highest_pw_len, pws_cnt, fast_iteration);
 
       if (data.devices_status == STATUS_STOP_AT_CHECKPOINT) check_checkpoint ();
 
@@ -3422,7 +3628,10 @@ static void run_cracker (hc_device_param_t *device_param, const uint pws_cnt)
        * result
        */
 
-      check_cracked (device_param, salt_pos);
+      if (data.benchmark == 0)
+      {
+        check_cracked (device_param, salt_pos);
+      }
 
       /**
        * progress
@@ -3816,7 +4025,7 @@ static void *thread_monitor (void *p)
   uint status_left  = data.status_timer;
 
   #ifdef HAVE_HWMON
-  uint hwmon_check   = 0;
+  uint hwmon_check = 0;
 
   int slowdown_warnings = 0;
 
@@ -3884,7 +4093,7 @@ static void *thread_monitor (void *p)
 
     #ifdef HAVE_HWMON
 
-    if (1)
+    if (hwmon_check == 1)
     {
       hc_thread_mutex_lock (mux_adl);
 
@@ -3894,35 +4103,47 @@ static void *thread_monitor (void *p)
 
         if (device_param->skipped) continue;
 
-        if ((data.devices_param[device_id].device_type & CL_DEVICE_TYPE_GPU) == 0) continue;
+        if (device_param->device_vendor_id == VENDOR_ID_NV)
+        {
+          if (data.hm_nvapi)
+          {
+            NV_GPU_PERF_POLICIES_INFO_PARAMS_V1   perfPolicies_info   = { 0 };
+            NV_GPU_PERF_POLICIES_STATUS_PARAMS_V1 perfPolicies_status = { 0 };
 
-        const int temperature = hm_get_temperature_with_device_id (device_id);
+            perfPolicies_info.version   = MAKE_NVAPI_VERSION (NV_GPU_PERF_POLICIES_INFO_PARAMS_V1, 1);
+            perfPolicies_status.version = MAKE_NVAPI_VERSION (NV_GPU_PERF_POLICIES_STATUS_PARAMS_V1, 1);
 
-        const int threshold = data.hm_device[device_id].gpu_temp_threshold_slowdown;
+            hm_NvAPI_GPU_GetPerfPoliciesInfo (data.hm_nvapi, data.hm_device[device_id].nvapi, &perfPolicies_info);
 
-        if (temperature >= threshold)
-        {
-          if (slowdown_warnings < 3)
-          {
-            if (data.quiet == 0) clear_prompt ();
+            perfPolicies_status.info_value = perfPolicies_info.info_value;
 
-            log_info ("WARNING: Drivers temperature threshold (%dc) hit on GPU #%d, expect performance to drop...", threshold, device_id + 1);
+            hm_NvAPI_GPU_GetPerfPoliciesStatus (data.hm_nvapi, data.hm_device[device_id].nvapi, &perfPolicies_status);
 
-            if (slowdown_warnings == 2)
+            if (perfPolicies_status.throttle & 2)
             {
-              log_info ("");
-            }
+              if (slowdown_warnings < 3)
+              {
+                if (data.quiet == 0) clear_prompt ();
+
+                log_info ("WARNING: Drivers temperature threshold hit on GPU #%d, expect performance to drop...", device_id + 1);
+
+                if (slowdown_warnings == 2)
+                {
+                  log_info ("");
+                }
 
-            if (data.quiet == 0) fprintf (stdout, "%s", PROMPT);
-            if (data.quiet == 0) fflush (stdout);
+                if (data.quiet == 0) fprintf (stdout, "%s", PROMPT);
+                if (data.quiet == 0) fflush (stdout);
 
-            slowdown_warnings++;
+                slowdown_warnings++;
+              }
+            }
+            else
+            {
+              slowdown_warnings = 0;
+            }
           }
         }
-        else
-        {
-          slowdown_warnings = 0;
-        }
       }
 
       hc_thread_mutex_unlock (mux_adl);
@@ -4431,14 +4652,43 @@ static void pw_add (hc_device_param_t *device_param, const u8 *pw_buf, const int
   //}
 }
 
-static u32 get_power (const u32 kernel_power)
+static void set_kernel_power_final (const u64 kernel_power_final)
+{
+  if (data.quiet == 0)
+  {
+    clear_prompt ();
+
+    //log_info ("");
+
+    log_info ("INFO: approaching final keyspace, workload adjusted");
+    log_info ("");
+
+    fprintf (stdout, "%s", PROMPT);
+
+    fflush (stdout);
+  }
+
+  data.kernel_power_final = kernel_power_final;
+}
+
+static u32 get_power (hc_device_param_t *device_param)
 {
-  if (data.kernel_power_div)
+  const u64 kernel_power_final = data.kernel_power_final;
+
+  if (kernel_power_final)
   {
-    return (float) kernel_power * data.kernel_power_div;
+    const double device_factor = (double) device_param->hardware_power / data.hardware_power_all;
+
+    const u64 words_left_device = CEIL ((double) kernel_power_final * device_factor);
+
+    // work should be at least the hardware power available without any accelerator
+
+    const u64 work = MAX (words_left_device, device_param->hardware_power);
+
+    return work;
   }
 
-  return kernel_power;
+  return device_param->kernel_power;
 }
 
 static uint get_work (hc_device_param_t *device_param, const u64 max)
@@ -4450,17 +4700,19 @@ static uint get_work (hc_device_param_t *device_param, const u64 max)
 
   device_param->words_off = words_cur;
 
+  const u64 kernel_power_all = data.kernel_power_all;
+
   const u64 words_left = words_base - words_cur;
 
-  if (data.kernel_power_all > words_left)
+  if (words_left < kernel_power_all)
   {
-    if (data.kernel_power_div == 0)
+    if (data.kernel_power_final == 0)
     {
-      data.kernel_power_div = find_kernel_power_div (words_left, data.kernel_power_all);
+      set_kernel_power_final (words_left);
     }
   }
 
-  const u32 kernel_power = get_power (device_param->kernel_power);
+  const u32 kernel_power = get_power (device_param);
 
   uint work = MIN (words_left, kernel_power);
 
@@ -4507,7 +4759,7 @@ static void *thread_calc_stdin (void *p)
 
     uint words_cur = 0;
 
-    while (words_cur < get_power (device_param->kernel_power))
+    while (words_cur < device_param->kernel_power)
     {
       char *line_buf = fgets (buf, HCBUFSIZ - 1, stdin);
 
@@ -4541,6 +4793,8 @@ static void *thread_calc_stdin (void *p)
         continue;
       }
 
+      // hmm that's always the case, or?
+
       if (attack_kern == ATTACK_KERN_STRAIGHT)
       {
         if ((line_len < data.pw_min) || (line_len > data.pw_max))
@@ -4557,25 +4811,6 @@ static void *thread_calc_stdin (void *p)
           continue;
         }
       }
-      else if (attack_kern == ATTACK_KERN_COMBI)
-      {
-        // do not check if minimum restriction is satisfied (line_len >= data.pw_min) here
-        // since we still need to combine the plains
-
-        if (line_len > data.pw_max)
-        {
-          hc_thread_mutex_lock (mux_counter);
-
-          for (uint salt_pos = 0; salt_pos < data.salts_cnt; salt_pos++)
-          {
-            data.words_progress_rejected[salt_pos] += data.combs_cnt;
-          }
-
-          hc_thread_mutex_unlock (mux_counter);
-
-          continue;
-        }
-      }
 
       pw_add (device_param, (u8 *) line_buf, line_len);
 
@@ -4954,11 +5189,11 @@ static void weak_hash_check (hc_device_param_t *device_param, const uint salt_po
 
   if (data.attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
   {
-    run_kernel (KERN_RUN_1, device_param, 1, false);
+    run_kernel (KERN_RUN_1, device_param, 1, false, 0);
   }
   else
   {
-    run_kernel (KERN_RUN_1, device_param, 1, false);
+    run_kernel (KERN_RUN_1, device_param, 1, false, 0);
 
     uint loop_step = 16;
 
@@ -4973,10 +5208,10 @@ static void weak_hash_check (hc_device_param_t *device_param, const uint salt_po
       device_param->kernel_params_buf32[25] = loop_pos;
       device_param->kernel_params_buf32[26] = loop_left;
 
-      run_kernel (KERN_RUN_2, device_param, 1, false);
+      run_kernel (KERN_RUN_2, device_param, 1, false, 0);
     }
 
-    run_kernel (KERN_RUN_3, device_param, 1, false);
+    run_kernel (KERN_RUN_3, device_param, 1, false, 0);
   }
 
   /**
@@ -5360,7 +5595,7 @@ static uint hlfmt_detect (FILE *fp, uint max_check)
 // wrapper around mymalloc for ADL
 
 #if defined(HAVE_HWMON)
-void *__stdcall ADL_Main_Memory_Alloc (const int iSize)
+void *HC_API_CALL ADL_Main_Memory_Alloc (const int iSize)
 {
   return mymalloc (iSize);
 }
@@ -5382,8 +5617,6 @@ static uint generate_bitmaps (const uint digests_cnt, const uint dgst_size, cons
 
   for (uint i = 0; i < digests_cnt; i++)
   {
-    if (data.digests_shown[i] == 1) continue; // can happen with potfile
-
     uint *digest_ptr = (uint *) digests_buf_ptr;
 
     digests_buf_ptr += dgst_size;
@@ -5418,7 +5651,7 @@ static uint generate_bitmaps (const uint digests_cnt, const uint dgst_size, cons
  * main
  */
 
-#ifdef _WIN
+#ifdef WIN
 void SetConsoleWindowSize (const int x)
 {
   HANDLE h = GetStdHandle (STD_OUTPUT_HANDLE);
@@ -5435,8 +5668,8 @@ void SetConsoleWindowSize (const int x)
 
   COORD co;
 
-  co.X = sr->Right  + 1;
-  co.Y = sr->Bottom + 1;
+  co.X = sr->Right + 1;
+  co.Y = 9999;
 
   if (!SetConsoleScreenBufferSize (h, co)) return;
 
@@ -5446,7 +5679,7 @@ void SetConsoleWindowSize (const int x)
 
 int main (int argc, char **argv)
 {
-  #ifdef _WIN
+  #ifdef WIN
   SetConsoleWindowSize (132);
   #endif
 
@@ -5515,6 +5748,7 @@ int main (int argc, char **argv)
   uint  version                   = VERSION;
   uint  quiet                     = QUIET;
   uint  benchmark                 = BENCHMARK;
+  uint  stdout_flag               = STDOUT_FLAG;
   uint  show                      = SHOW;
   uint  left                      = LEFT;
   uint  username                  = USERNAME;
@@ -5612,6 +5846,7 @@ int main (int argc, char **argv)
   #define IDX_FORCE                     0xff08
   #define IDX_RUNTIME                   0xff09
   #define IDX_BENCHMARK                 'b'
+  #define IDX_STDOUT_FLAG               0xff77
   #define IDX_HASH_MODE                 'm'
   #define IDX_ATTACK_MODE               'a'
   #define IDX_RP_FILE                   'r'
@@ -5692,6 +5927,7 @@ int main (int argc, char **argv)
     {"outfile-check-dir",         required_argument, 0, IDX_OUTFILE_CHECK_DIR},
     {"force",                     no_argument,       0, IDX_FORCE},
     {"benchmark",                 no_argument,       0, IDX_BENCHMARK},
+    {"stdout",                    no_argument,       0, IDX_STDOUT_FLAG},
     {"restore",                   no_argument,       0, IDX_RESTORE},
     {"restore-disable",           no_argument,       0, IDX_RESTORE_DISABLE},
     {"status",                    no_argument,       0, IDX_STATUS},
@@ -5988,6 +6224,7 @@ int main (int argc, char **argv)
       case IDX_LIMIT:                     limit                     = atoll (optarg); break;
       case IDX_KEYSPACE:                  keyspace                  = 1;              break;
       case IDX_BENCHMARK:                 benchmark                 = 1;              break;
+      case IDX_STDOUT_FLAG:               stdout_flag               = 1;              break;
       case IDX_RESTORE:                                                               break;
       case IDX_RESTORE_DISABLE:           restore_disable           = 1;              break;
       case IDX_STATUS:                    status                    = 1;              break;
@@ -6087,6 +6324,9 @@ int main (int argc, char **argv)
       {
         log_info ("%s (%s) starting in benchmark-mode...", PROGNAME, VERSION_TAG);
         log_info ("");
+        log_info ("Note: Reported benchmark cracking speed = real cracking speed");
+        log_info ("To verify, run hashcat like this: only_one_hash.txt -a 3 -w 3 ?b?b?b?b?b?b?b");
+        log_info ("");
       }
       else
       {
@@ -6098,6 +6338,10 @@ int main (int argc, char **argv)
       log_info ("%s (%s) starting in restore-mode...", PROGNAME, VERSION_TAG);
       log_info ("");
     }
+    else if (stdout_flag == 1)
+    {
+      // do nothing
+    }
     else
     {
       log_info ("%s (%s) starting...", PROGNAME, VERSION_TAG);
@@ -6123,7 +6367,7 @@ int main (int argc, char **argv)
     return (-1);
   }
 
-  if (hash_mode_chgd && hash_mode > 13799) // just added to remove compiler warnings for hash_mode_chgd
+  if (hash_mode_chgd && hash_mode > 13800) // just added to remove compiler warnings for hash_mode_chgd
   {
     log_error ("ERROR: Invalid hash-type specified");
 
@@ -6361,8 +6605,32 @@ int main (int argc, char **argv)
     case ATTACK_MODE_HYBRID2:  attack_kern = ATTACK_KERN_COMBI;    break;
   }
 
-  if (benchmark == 0)
+  if (benchmark == 1)
   {
+    if (myargv[optind] != 0)
+    {
+      log_error ("ERROR: Invalid argument for benchmark mode specified");
+
+      return (-1);
+    }
+
+    if (attack_mode_chgd == 1)
+    {
+      if (attack_mode != ATTACK_MODE_BF)
+      {
+        log_error ("ERROR: Only attack-mode 3 allowed in benchmark mode");
+
+        return (-1);
+      }
+    }
+  }
+  else
+  {
+    if (stdout_flag == 1) // no hash here
+    {
+      optind--;
+    }
+
     if (keyspace == 1)
     {
       int num_additional_params = 1;
@@ -6420,25 +6688,6 @@ int main (int argc, char **argv)
       return (-1);
     }
   }
-  else
-  {
-    if (myargv[optind] != 0)
-    {
-      log_error ("ERROR: Invalid argument for benchmark mode specified");
-
-      return (-1);
-    }
-
-    if (attack_mode_chgd == 1)
-    {
-      if (attack_mode != ATTACK_MODE_BF)
-      {
-        log_error ("ERROR: Only attack-mode 3 allowed in benchmark mode");
-
-        return (-1);
-      }
-    }
-  }
 
   if (skip != 0 && limit != 0)
   {
@@ -6471,6 +6720,24 @@ int main (int argc, char **argv)
     quiet = 1;
   }
 
+  if (stdout_flag == 1)
+  {
+    status_timer          = 0;
+    restore_timer         = 0;
+    restore_disable       = 1;
+    restore               = 0;
+    potfile_disable       = 1;
+    weak_hash_threshold   = 0;
+    gpu_temp_disable      = 1;
+    hash_mode             = 2000;
+    quiet                 = 1;
+    outfile_format        = OUTFILE_FMT_PLAIN;
+    kernel_accel          = 1024;
+    kernel_loops          = 1024;
+    force                 = 1;
+    outfile_check_timer   = 0;
+  }
+
   if (remove_timer_chgd == 1)
   {
     if (remove == 0)
@@ -6817,6 +7084,7 @@ int main (int argc, char **argv)
   logfile_top_uint   (attack_mode);
   logfile_top_uint   (attack_kern);
   logfile_top_uint   (benchmark);
+  logfile_top_uint   (stdout_flag);
   logfile_top_uint   (bitmap_min);
   logfile_top_uint   (bitmap_max);
   logfile_top_uint   (debug_mode);
@@ -6943,14 +7211,19 @@ int main (int argc, char **argv)
     potfile_disable       = 1;
     weak_hash_threshold   = 0;
     gpu_temp_disable      = 1;
+    outfile_check_timer   = 0;
 
     #ifdef HAVE_HWMON
-    powertune_enable      = 1;
+    if (powertune_enable == 1)
+    {
+      gpu_temp_disable = 0;
+    }
     #endif
 
-    data.status_timer     = status_timer;
-    data.restore_timer    = restore_timer;
-    data.restore_disable  = restore_disable;
+    data.status_timer         = status_timer;
+    data.restore_timer        = restore_timer;
+    data.restore_disable      = restore_disable;
+    data.outfile_check_timer  = outfile_check_timer;
 
     /**
      * force attack mode to be bruteforce
@@ -8382,6 +8655,21 @@ int main (int argc, char **argv)
                    dgst_pos3   = 3;
                    break;
 
+      case  2000:  hash_type   = HASH_TYPE_STDOUT;
+                   salt_type   = SALT_TYPE_NONE;
+                   attack_exec = ATTACK_EXEC_INSIDE_KERNEL;
+                   opts_type   = OPTS_TYPE_PT_GENERATE_LE;
+                   kern_type   = 0;
+                   dgst_size   = DGST_SIZE_4_4;
+                   parse_func  = NULL;
+                   sort_by_digest = NULL;
+                   opti_type   = 0;
+                   dgst_pos0   = 0;
+                   dgst_pos1   = 0;
+                   dgst_pos2   = 0;
+                   dgst_pos3   = 0;
+                   break;
+
       case  2100:  hash_type   = HASH_TYPE_DCC2;
                    salt_type   = SALT_TYPE_EMBEDDED;
                    attack_exec = ATTACK_EXEC_OUTSIDE_KERNEL;
@@ -10796,6 +11084,25 @@ int main (int argc, char **argv)
                    dgst_pos3   = 3;
                    break;
 
+      case 13800:  hash_type   = HASH_TYPE_SHA256;
+                   salt_type   = SALT_TYPE_EMBEDDED;
+                   attack_exec = ATTACK_EXEC_INSIDE_KERNEL;
+                   opts_type   = OPTS_TYPE_PT_GENERATE_BE
+                               | OPTS_TYPE_PT_UNICODE;
+                   kern_type   = KERN_TYPE_WIN8PHONE;
+                   dgst_size   = DGST_SIZE_4_8;
+                   parse_func  = win8phone_parse_hash;
+                   sort_by_digest = sort_by_digest_4_8;
+                   opti_type   = OPTI_TYPE_ZERO_BYTE
+                               | OPTI_TYPE_PRECOMPUTE_INIT
+                               | OPTI_TYPE_EARLY_SKIP
+                               | OPTI_TYPE_NOT_ITERATED
+                               | OPTI_TYPE_RAW_HASH;
+                   dgst_pos0   = 3;
+                   dgst_pos1   = 7;
+                   dgst_pos2   = 2;
+                   dgst_pos3   = 6;
+                   break;
 
       default:     usage_mini_print (PROGNAME); return (-1);
     }
@@ -10922,6 +11229,7 @@ int main (int argc, char **argv)
       case 13761:  esalt_size = sizeof (tc_t);            break;
       case 13762:  esalt_size = sizeof (tc_t);            break;
       case 13763:  esalt_size = sizeof (tc_t);            break;
+      case 13800:  esalt_size = sizeof (win8phone_t);     break;
     }
 
     data.esalt_size = esalt_size;
@@ -11255,7 +11563,7 @@ int main (int argc, char **argv)
                   break;
       case  7400: if (pw_max > 16) pw_max = 16;
                   break;
-      case  7500: if (pw_max >  8) pw_max =  8;
+      case  7700: if (pw_max >  8) pw_max =  8;
                   break;
       case  7900: if (pw_max > 48) pw_max = 48;
                   break;
@@ -11324,7 +11632,7 @@ int main (int argc, char **argv)
 
     uint hashes_avail = 0;
 
-    if (benchmark == 0)
+    if ((benchmark == 0) && (stdout_flag == 0))
     {
       struct stat f;
 
@@ -11506,6 +11814,10 @@ int main (int argc, char **argv)
       {
         // useless to read hash file for keyspace, cheat a little bit w/ optind
       }
+      else if (stdout_flag == 1)
+      {
+        // useless to read hash file for stdout, cheat a little bit w/ optind
+      }
       else if (hashes_avail == 0)
       {
       }
@@ -12315,7 +12627,7 @@ int main (int argc, char **argv)
       return (0);
     }
 
-    if (keyspace == 0)
+    if ((keyspace == 0) && (stdout_flag == 0))
     {
       if (hashes_cnt == 0)
       {
@@ -13671,10 +13983,16 @@ int main (int argc, char **argv)
         {
           if (device_param->device_vendor_id == VENDOR_ID_AMD_USE_INTEL)
           {
-            log_info ("Device #%u: WARNING: not native intel opencl runtime, expect massive speed loss", device_id + 1);
-            log_info ("           You can use --force to override this but do not post error reports if you do so");
+            if (data.force == 0)
+            {
+              if (algorithm_pos == 0)
+              {
+                log_info ("Device #%u: WARNING: not native intel opencl runtime, expect massive speed loss", device_id + 1);
+                log_info ("           You can use --force to override this but do not post error reports if you do so");
+              }
 
-            if (data.force == 0) device_param->skipped = 1;
+              device_param->skipped = 1;
+            }
           }
         }
 
@@ -14001,9 +14319,9 @@ int main (int argc, char **argv)
      */
 
     #ifdef HAVE_HWMON
-    hm_attrs_t hm_adapters_adl[DEVICES_MAX]   = { { { 0 }, 0, 0, 0, 0, 0 } };
-    hm_attrs_t hm_adapters_nvapi[DEVICES_MAX] = { { { 0 }, 0, 0, 0, 0, 0 } };
-    hm_attrs_t hm_adapters_nvml[DEVICES_MAX]  = { { { 0 }, 0, 0, 0, 0, 0 } };
+    hm_attrs_t hm_adapters_adl[DEVICES_MAX]   = { { 0 } };
+    hm_attrs_t hm_adapters_nvapi[DEVICES_MAX] = { { 0 } };
+    hm_attrs_t hm_adapters_nvml[DEVICES_MAX]  = { { 0 } };
 
     if (gpu_temp_disable == 0)
     {
@@ -14032,18 +14350,18 @@ int main (int argc, char **argv)
 
           for (int i = 0; i < tmp_in; i++)
           {
-            hm_adapters_nvml[tmp_out++].adapter_index.nvml = nvmlGPUHandle[i];
+            hm_adapters_nvml[tmp_out++].nvml = nvmlGPUHandle[i];
           }
 
           for (int i = 0; i < tmp_out; i++)
           {
             unsigned int speed;
 
-            if (hm_NVML_nvmlDeviceGetFanSpeed (data.hm_nvml, 0, hm_adapters_nvml[i].adapter_index.nvml, &speed) == NVML_SUCCESS) hm_adapters_nvml[i].fan_get_supported = 1;
+            if (hm_NVML_nvmlDeviceGetFanSpeed (data.hm_nvml, 0, hm_adapters_nvml[i].nvml, &speed) == NVML_SUCCESS) hm_adapters_nvml[i].fan_get_supported = 1;
 
-            hm_NVML_nvmlDeviceSetComputeMode (data.hm_nvml, 1, hm_adapters_nvml[i].adapter_index.nvml, NVML_COMPUTEMODE_EXCLUSIVE_PROCESS);
+            hm_NVML_nvmlDeviceSetComputeMode (data.hm_nvml, 1, hm_adapters_nvml[i].nvml, NVML_COMPUTEMODE_EXCLUSIVE_PROCESS);
 
-            hm_NVML_nvmlDeviceSetGpuOperationMode (data.hm_nvml, 1, hm_adapters_nvml[i].adapter_index.nvml, NVML_GOM_ALL_ON);
+            hm_NVML_nvmlDeviceSetGpuOperationMode (data.hm_nvml, 1, hm_adapters_nvml[i].nvml, NVML_GOM_ALL_ON);
           }
         }
       }
@@ -14065,7 +14383,7 @@ int main (int argc, char **argv)
 
           for (int i = 0; i < tmp_in; i++)
           {
-            hm_adapters_nvapi[tmp_out++].adapter_index.nvapi = nvGPUHandle[i];
+            hm_adapters_nvapi[tmp_out++].nvapi = nvGPUHandle[i];
           }
         }
       }
@@ -14250,14 +14568,24 @@ int main (int argc, char **argv)
 
         const uint platform_devices_id = device_param->platform_devices_id;
 
-        if (device_param->device_vendor_id == VENDOR_ID_NV)
+        if (device_param->device_vendor_id == VENDOR_ID_AMD)
         {
-          memcpy (&data.hm_device[device_id], &hm_adapters_nvml[platform_devices_id], sizeof (hm_attrs_t));
+          data.hm_device[device_id].adl               = hm_adapters_adl[platform_devices_id].adl;
+          data.hm_device[device_id].nvapi             = 0;
+          data.hm_device[device_id].nvml              = 0;
+          data.hm_device[device_id].od_version        = hm_adapters_adl[platform_devices_id].od_version;
+          data.hm_device[device_id].fan_get_supported = hm_adapters_adl[platform_devices_id].fan_get_supported;
+          data.hm_device[device_id].fan_set_supported = hm_adapters_adl[platform_devices_id].fan_set_supported;
         }
 
-        if (device_param->device_vendor_id == VENDOR_ID_AMD)
+        if (device_param->device_vendor_id == VENDOR_ID_NV)
         {
-          memcpy (&data.hm_device[device_id], &hm_adapters_adl[platform_devices_id], sizeof (hm_attrs_t));
+          data.hm_device[device_id].adl               = 0;
+          data.hm_device[device_id].nvapi             = hm_adapters_nvapi[platform_devices_id].nvapi;
+          data.hm_device[device_id].nvml              = hm_adapters_nvml[platform_devices_id].nvml;
+          data.hm_device[device_id].od_version        = 0;
+          data.hm_device[device_id].fan_get_supported = hm_adapters_nvml[platform_devices_id].fan_get_supported;
+          data.hm_device[device_id].fan_set_supported = 0;
         }
       }
     }
@@ -14294,7 +14622,7 @@ int main (int argc, char **argv)
 
             int powertune_supported = 0;
 
-            if ((ADL_rc = hm_ADL_Overdrive6_PowerControl_Caps (data.hm_adl, data.hm_device[device_id].adapter_index.adl, &powertune_supported)) != ADL_OK)
+            if ((ADL_rc = hm_ADL_Overdrive6_PowerControl_Caps (data.hm_adl, data.hm_device[device_id].adl, &powertune_supported)) != ADL_OK)
             {
               log_error ("ERROR: Failed to get ADL PowerControl Capabilities");
 
@@ -14309,9 +14637,9 @@ int main (int argc, char **argv)
 
               ADLOD6PowerControlInfo powertune = {0, 0, 0, 0, 0};
 
-              if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_adl, data.hm_device[device_id].adapter_index.adl, &powertune)) == ADL_OK)
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_adl, data.hm_device[device_id].adl, &powertune)) == ADL_OK)
               {
-                ADL_rc = hm_ADL_Overdrive_PowerControl_Get (data.hm_adl, data.hm_device[device_id].adapter_index.adl, &od_power_control_status[device_id]);
+                ADL_rc = hm_ADL_Overdrive_PowerControl_Get (data.hm_adl, data.hm_device[device_id].adl, &od_power_control_status[device_id]);
               }
 
               if (ADL_rc != ADL_OK)
@@ -14321,7 +14649,7 @@ int main (int argc, char **argv)
                 return (-1);
               }
 
-              if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adapter_index.adl, powertune.iMaxValue)) != ADL_OK)
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adl, powertune.iMaxValue)) != ADL_OK)
               {
                 log_error ("ERROR: Failed to set new ADL PowerControl values");
 
@@ -14334,7 +14662,7 @@ int main (int argc, char **argv)
 
               od_clock_mem_status[device_id].state.iNumberOfPerformanceLevels = 2;
 
-              if ((ADL_rc = hm_ADL_Overdrive_StateInfo_Get (data.hm_adl, data.hm_device[device_id].adapter_index.adl, ADL_OD6_GETSTATEINFO_CUSTOM_PERFORMANCE, &od_clock_mem_status[device_id])) != ADL_OK)
+              if ((ADL_rc = hm_ADL_Overdrive_StateInfo_Get (data.hm_adl, data.hm_device[device_id].adl, ADL_OD6_GETSTATEINFO_CUSTOM_PERFORMANCE, &od_clock_mem_status[device_id])) != ADL_OK)
               {
                 log_error ("ERROR: Failed to get ADL memory and engine clock frequency");
 
@@ -14345,7 +14673,7 @@ int main (int argc, char **argv)
 
               ADLOD6Capabilities caps = {0, 0, 0, {0, 0, 0}, {0, 0, 0}, 0, 0};
 
-              if ((ADL_rc = hm_ADL_Overdrive_Capabilities_Get (data.hm_adl, data.hm_device[device_id].adapter_index.adl, &caps)) != ADL_OK)
+              if ((ADL_rc = hm_ADL_Overdrive_Capabilities_Get (data.hm_adl, data.hm_device[device_id].adl, &caps)) != ADL_OK)
               {
                 log_error ("ERROR: Failed to get ADL device capabilities");
 
@@ -14382,7 +14710,7 @@ int main (int argc, char **argv)
               performance_state->aLevels[0].iMemoryClock = memory_clock_profile_max;
               performance_state->aLevels[1].iMemoryClock = memory_clock_profile_max;
 
-              if ((ADL_rc = hm_ADL_Overdrive_State_Set (data.hm_adl, data.hm_device[device_id].adapter_index.adl, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
+              if ((ADL_rc = hm_ADL_Overdrive_State_Set (data.hm_adl, data.hm_device[device_id].adl, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
               {
                 log_info ("ERROR: Failed to set ADL performance state");
 
@@ -14399,14 +14727,14 @@ int main (int argc, char **argv)
               // powertune set
               ADLOD6PowerControlInfo powertune = {0, 0, 0, 0, 0};
 
-              if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_adl, data.hm_device[device_id].adapter_index.adl, &powertune)) != ADL_OK)
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_adl, data.hm_device[device_id].adl, &powertune)) != ADL_OK)
               {
                 log_error ("ERROR: Failed to get current ADL PowerControl settings");
 
                 return (-1);
               }
 
-              if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adapter_index.adl, powertune.iMaxValue)) != ADL_OK)
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adl, powertune.iMaxValue)) != ADL_OK)
               {
                 log_error ("ERROR: Failed to set new ADL PowerControl values");
 
@@ -14424,7 +14752,7 @@ int main (int argc, char **argv)
 
           int powertune_supported = 0;
 
-          if (hm_NVML_nvmlDeviceGetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].adapter_index.nvml, &limit) == NVML_SUCCESS)
+          if (hm_NVML_nvmlDeviceGetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].nvml, &limit) == NVML_SUCCESS)
           {
             powertune_supported = 1;
           }
@@ -14436,11 +14764,11 @@ int main (int argc, char **argv)
             unsigned int minLimit;
             unsigned int maxLimit;
 
-            if (hm_NVML_nvmlDeviceGetPowerManagementLimitConstraints (data.hm_nvml, 0, data.hm_device[device_id].adapter_index.nvml, &minLimit, &maxLimit) == NVML_SUCCESS)
+            if (hm_NVML_nvmlDeviceGetPowerManagementLimitConstraints (data.hm_nvml, 0, data.hm_device[device_id].nvml, &minLimit, &maxLimit) == NVML_SUCCESS)
             {
               if (maxLimit > 0)
               {
-                if (hm_NVML_nvmlDeviceSetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].adapter_index.nvml, maxLimit) == NVML_SUCCESS)
+                if (hm_NVML_nvmlDeviceSetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].nvml, maxLimit) == NVML_SUCCESS)
                 {
                   // now we can be sure we need to reset later
 
@@ -14525,6 +14853,8 @@ int main (int argc, char **argv)
 
       device_param->kernel_threads = kernel_threads;
 
+      device_param->hardware_power = device_processors * kernel_threads;
+
       /**
        * create input buffers on device : calculate size of fixed memory buffers
        */
@@ -14639,7 +14969,7 @@ int main (int argc, char **argv)
        * some algorithms need a fixed kernel-loops count
        */
 
-      if (hash_mode == 1500)
+      if (hash_mode == 1500 && attack_mode == ATTACK_MODE_BF)
       {
         const u32 kernel_loops_fixed = 1024;
 
@@ -14647,7 +14977,7 @@ int main (int argc, char **argv)
         device_param->kernel_loops_max = kernel_loops_fixed;
       }
 
-      if (hash_mode == 3000)
+      if (hash_mode == 3000 && attack_mode == ATTACK_MODE_BF)
       {
         const u32 kernel_loops_fixed = 1024;
 
@@ -14814,7 +15144,9 @@ int main (int argc, char **argv)
 
         if ((opts_type & OPTS_TYPE_HOOK12) || (opts_type & OPTS_TYPE_HOOK23))
         {
-          // none yet
+          switch (hash_mode)
+          {
+          }
         }
 
         // now check if all device-memory sizes which depend on the kernel_accel_max amplifier are within its boundaries
@@ -15735,21 +16067,6 @@ int main (int argc, char **argv)
 
       #if defined(HAVE_HWMON)
 
-      /**
-       * Store thermal target temperature so we can send a notice to user
-       */
-
-      if (gpu_temp_disable == 0)
-      {
-        const int gpu_temp_threshold_slowdown = hm_get_threshold_slowdown_with_device_id (device_id);
-        const int gpu_temp_threshold_shutdown = hm_get_threshold_slowdown_with_device_id (device_id);
-
-        data.hm_device[device_id].gpu_temp_threshold_slowdown = (gpu_temp_threshold_slowdown > 0) ? gpu_temp_threshold_slowdown : 10000;
-        data.hm_device[device_id].gpu_temp_threshold_shutdown = (gpu_temp_threshold_shutdown > 0) ? gpu_temp_threshold_shutdown : 10000;
-
-        // we could use those numbers for gpu_temp_retain and gpu_temp_abort, too
-      }
-
       /**
        * Store initial fanspeed if gpu_temp_retain is enabled
        */
@@ -16680,11 +16997,18 @@ int main (int argc, char **argv)
 
     if (data.devices_status != STATUS_CRACKED) data.devices_status = STATUS_STARTING;
 
-    hc_thread_t i_thread = 0;
+    uint i_threads_cnt = 0;
+
+    hc_thread_t *i_threads = (hc_thread_t *) mycalloc (10, sizeof (hc_thread_t));
 
     if ((data.wordlist_mode == WL_MODE_FILE) || (data.wordlist_mode == WL_MODE_MASK))
     {
-      hc_thread_create (i_thread, thread_keypress, &benchmark);
+      if (stdout_flag == 0)
+      {
+        hc_thread_create (i_threads[i_threads_cnt], thread_keypress, &benchmark);
+
+        i_threads_cnt++;
+      }
     }
 
     if (wordlist_mode == WL_MODE_STDIN) data.status = 1;
@@ -16693,9 +17017,12 @@ int main (int argc, char **argv)
 
     hc_thread_t *ni_threads = (hc_thread_t *) mycalloc (10, sizeof (hc_thread_t));
 
-    hc_thread_create (ni_threads[ni_threads_cnt], thread_monitor, NULL);
+    if (stdout_flag == 0)
+    {
+      hc_thread_create (ni_threads[ni_threads_cnt], thread_monitor, NULL);
 
-    ni_threads_cnt++;
+      ni_threads_cnt++;
+    }
 
     /**
       * Outfile remove
@@ -17034,7 +17361,7 @@ int main (int argc, char **argv)
 
         data.ms_paused = 0;
 
-        data.kernel_power_div = 0;
+        data.kernel_power_final = 0;
 
         data.words_cur = rd->words_cur;
 
@@ -17544,37 +17871,14 @@ int main (int argc, char **argv)
           }
         }
 
-        data.devices_status = STATUS_RUNNING;
-
-        if (initial_restore_done == 0)
-        {
-          if (data.restore_disable == 0) cycle_restore ();
-
-          initial_restore_done = 1;
-        }
-
-        hc_timer_set (&data.timer_running);
-
-        if ((wordlist_mode == WL_MODE_FILE) || (wordlist_mode == WL_MODE_MASK))
-        {
-          if ((quiet == 0) && (status == 0) && (benchmark == 0))
-          {
-            if (quiet == 0) fprintf (stdout, "%s", PROMPT);
-            if (quiet == 0) fflush (stdout);
-          }
-        }
-        else if (wordlist_mode == WL_MODE_STDIN)
-        {
-          if (data.quiet == 0) log_info ("Starting attack in stdin mode...");
-          if (data.quiet == 0) log_info ("");
-        }
-
         /**
          * create autotune threads
          */
 
         hc_thread_t *c_threads = (hc_thread_t *) mycalloc (data.devices_cnt, sizeof (hc_thread_t));
 
+        data.devices_status = STATUS_AUTOTUNE;
+
         for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
         {
           hc_device_param_t *device_param = &devices_param[device_id];
@@ -17588,15 +17892,21 @@ int main (int argc, char **argv)
          * Inform user about possible slow speeds
          */
 
+        uint hardware_power_all = 0;
+
         uint kernel_power_all = 0;
 
         for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
         {
           hc_device_param_t *device_param = &devices_param[device_id];
 
+          hardware_power_all += device_param->hardware_power;
+
           kernel_power_all += device_param->kernel_power;
         }
 
+        data.hardware_power_all = hardware_power_all; // hardware_power_all is the same as kernel_power_all but without the influence of kernel_accel on the devices
+
         data.kernel_power_all = kernel_power_all;
 
         if ((wordlist_mode == WL_MODE_FILE) || (wordlist_mode == WL_MODE_MASK))
@@ -17619,6 +17929,31 @@ int main (int argc, char **argv)
          * create cracker threads
          */
 
+        data.devices_status = STATUS_RUNNING;
+
+        if (initial_restore_done == 0)
+        {
+          if (data.restore_disable == 0) cycle_restore ();
+
+          initial_restore_done = 1;
+        }
+
+        hc_timer_set (&data.timer_running);
+
+        if ((wordlist_mode == WL_MODE_FILE) || (wordlist_mode == WL_MODE_MASK))
+        {
+          if ((quiet == 0) && (status == 0) && (benchmark == 0))
+          {
+            if (quiet == 0) fprintf (stdout, "%s", PROMPT);
+            if (quiet == 0) fflush (stdout);
+          }
+        }
+        else if (wordlist_mode == WL_MODE_STDIN)
+        {
+          if (data.quiet == 0) log_info ("Starting attack in stdin mode...");
+          if (data.quiet == 0) log_info ("");
+        }
+
         time_t runtime_start;
 
         time (&runtime_start);
@@ -17808,11 +18143,13 @@ int main (int argc, char **argv)
 
     // wait for interactive threads
 
-    if ((data.wordlist_mode == WL_MODE_FILE) || (data.wordlist_mode == WL_MODE_MASK))
+    for (uint thread_idx = 0; thread_idx < i_threads_cnt; thread_idx++)
     {
-      hc_thread_wait (1, &i_thread);
+      hc_thread_wait (1, &i_threads[thread_idx]);
     }
 
+    local_free (i_threads);
+
     // we dont need restore file anymore
     if (data.restore_disable == 0)
     {
@@ -17995,7 +18332,7 @@ int main (int argc, char **argv)
 
             int powertune_supported = 0;
 
-            if ((hm_ADL_Overdrive6_PowerControl_Caps (data.hm_adl, data.hm_device[device_id].adapter_index.adl, &powertune_supported)) != ADL_OK)
+            if ((hm_ADL_Overdrive6_PowerControl_Caps (data.hm_adl, data.hm_device[device_id].adl, &powertune_supported)) != ADL_OK)
             {
               log_error ("ERROR: Failed to get ADL PowerControl Capabilities");
 
@@ -18006,7 +18343,7 @@ int main (int argc, char **argv)
             {
               // powercontrol settings
 
-              if ((hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adapter_index.adl, od_power_control_status[device_id])) != ADL_OK)
+              if ((hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adl, od_power_control_status[device_id])) != ADL_OK)
               {
                 log_info ("ERROR: Failed to restore the ADL PowerControl values");
 
@@ -18024,7 +18361,7 @@ int main (int argc, char **argv)
               performance_state->aLevels[0].iMemoryClock = od_clock_mem_status[device_id].state.aLevels[0].iMemoryClock;
               performance_state->aLevels[1].iMemoryClock = od_clock_mem_status[device_id].state.aLevels[1].iMemoryClock;
 
-              if ((hm_ADL_Overdrive_State_Set (data.hm_adl, data.hm_device[device_id].adapter_index.adl, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
+              if ((hm_ADL_Overdrive_State_Set (data.hm_adl, data.hm_device[device_id].adl, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
               {
                 log_info ("ERROR: Failed to restore ADL performance state");
 
@@ -18042,7 +18379,7 @@ int main (int argc, char **argv)
 
           if (limit > 0)
           {
-            hm_NVML_nvmlDeviceSetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].adapter_index.nvml, limit);
+            hm_NVML_nvmlDeviceSetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].nvml, limit);
           }
         }
       }