1 /*
2 *
3 * Ophcrack is a Lanmanager/NTLM hash cracker based on the faster time-memory
4 * trade-off using rainbow tables.
5 *
6 * Created with the help of: Maxime Mueller, Luca Wullschleger, Claude
7 * Hochreutiner, Andreas Huber and Etienne Dysli.
8 *
9 * Copyright (c) 2008 Philippe Oechslin, Cedric Tissieres, Bertrand Mesot
10 *
11 * Ophcrack is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Ophcrack is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Ophcrack; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 * This program is released under the GPL with the additional exemption
26 * that compiling, linking, and/or using OpenSSL is allowed.
27 *
28 *
29 *
30 *
31 */
32 #include <QHeaderView>
33 #include <QMessageBox>
34 #include <QTimer>
35 #include <QMenu>
36 #include <assert.h>
37 #include <math.h>
38 #include <config.h>
39
40 #include "ophcrackgui.h"
41 #include "hash.h"
42 #include "ophtask.h"
43 #include "list.h"
44 #include "message.h"
45 #include "original.h"
46 #include "singlehashdialog.h"
47 #include "aboutdialog.h"
48 //---------------------------------------------------------------------------
OphcrackGUI(ophcrack_t * crack)49 OphcrackGUI::OphcrackGUI(ophcrack_t *crack) : QMainWindow() {
50 setupUi(this);
51
52 this->crack = crack;
53 this->arg = crack->arg;
54 this->fsm = fsm_alloc(crack);
55
56 tableDialog = 0;
57 helpDialog = 0;
58 exportDialog = 0;
59 graphDialog = 0;
60
61 fsm_reset_preload(fsm);
62 fsm_reset_bforce(fsm);
63 resetTime();
64
65 // Setup the model which will display the hashes.
66
67 hashModel = new HashModel(hashView, arg->auditmode);
68 hashView->setModel(hashModel);
69 hashSelModel = hashView->selectionModel();
70
71 connect(hashView, SIGNAL(delSelection()), this, SLOT(delSelection()));
72 connect(hashModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
73 this, SLOT(addDelHash(const QModelIndex &, int, int)));
74
75 connect(hashModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
76 this, SLOT(addDelHash(const QModelIndex &, int, int)));
77
78 deleteButton->setEnabled(false);
79 saveButton->setEnabled(false);
80
81 // Insert into the model all the hashes which have been loaded
82 // before we start the GUI.
83
84 list_nd_t *nd;
85
86 for (nd = crack->hashes->head; nd != 0; nd = nd->next) {
87 hash_t *hsh = (hash_t*)nd->data;
88 hashModel->insertHash(hsh);
89 }
90
91 // Setup the model which we will use to display the tables.
92
93 tableModel = new TableModel(tableView);
94 tableView->setModel(tableModel);
95 tableView->hideColumn(TableModel::DIR_COL_IDX);
96
97 progDelegate = new ProgDelegate(tableView);
98 tableView->setItemDelegateForColumn(TableModel::PROGRESS_COL_IDX, progDelegate);
99
100 connect(tableModel, SIGNAL(itemChanged(QStandardItem*)),
101 this, SLOT(tableItemChanged(QStandardItem*)));
102
103 // Install the tables which have been specified on the command line.
104
105 list_t *table_str = crack->arg->table_str_cmd;
106
107 for (nd = table_str->head; nd != 0; nd = nd->next) {
108 char *tblstr = (char*)nd->data;
109 installTables(tblstr, true, false);
110 }
111
112 bool replace = table_str->size > 0 ? false : true;
113
114 // Install the tables given in the config file. Do not replace the
115 // table if some have already been installed from the command line.
116
117 table_str = crack->arg->table_str_conf;
118
119 for (nd = table_str->head; nd != 0; nd = nd->next) {
120 char *tblstr = (char*)nd->data;
121 installTables(tblstr, replace, false);
122 }
123
124 // Mark as not installed the tables which have not been loaded.
125
126 tableModel->insertRoot(lmalphanum5k);
127 tableModel->insertRoot(lmalphanum10k);
128 tableModel->insertRoot(lmextended);
129 tableModel->insertRoot(lmgermanv1);
130 tableModel->insertRoot(lmgermanv2);
131 tableModel->insertRoot(ntextended);
132 tableModel->insertRoot(ntdict);
133 tableModel->insertRoot(ntnine);
134 tableModel->insertRoot(nteight);
135 tableModel->insertRoot(ntnum);
136 tableModel->insertRoot(ntseven);
137 tableModel->insertRoot(lmflash);
138 tableModel->insertRoot(nteightxl);
139 tableModel->insertRoot(ntspecialxl);
140 tableModel->insertRoot(ntprobafree);
141 tableModel->insertRoot(ntproba10g);
142 tableModel->insertRoot(ntproba60g);
143
144 // Associate a menu to the load button.
145
146 loadMenu = new QMenu();
147 singleHash = loadMenu->addAction("Single hash");
148 hashFile = loadMenu->addAction("PWDUMP file");
149 sessFile = loadMenu->addAction("Session file");
150 samFile = loadMenu->addAction("Encrypted SAM");
151 #ifdef WIN32
152 localSam2 = loadMenu->addAction("Local SAM with samdump2");
153 #endif
154
155 connect(singleHash, SIGNAL(triggered()), this, SLOT(loadSingleHash()));
156 connect(hashFile, SIGNAL(triggered()), this, SLOT(loadHashFile()));
157 connect(samFile, SIGNAL(triggered()), this, SLOT(loadSamFile()));
158 connect(sessFile, SIGNAL(triggered()), this, SLOT(loadHashFile()));
159 #ifdef WIN32
160 connect(localSam2, SIGNAL(triggered()), this, SLOT(loadLocalSamSamdump()));
161 #endif
162
163 loadButton->setMenu(loadMenu);
164
165 // Associate a menu to the save button.
166
167 saveMenu = new QMenu();
168 saveFile = saveMenu->addAction("Save to file");
169 exportFile = saveMenu->addAction("Export to CSV");
170
171 connect(saveFile, SIGNAL(triggered()), this, SLOT(save()));
172 connect(exportFile, SIGNAL(triggered()), this, SLOT(exportCSV()));
173
174 saveButton->setMenu(saveMenu);
175
176 // Connect the other buttons.
177
178 connect(deleteButton, SIGNAL(clicked()), this, SLOT(delSelection()));
179 connect(crackButton, SIGNAL(clicked()), this, SLOT(startStopCrack()));
180 connect(tableButton, SIGNAL(clicked()), this, SLOT(selectTables()));
181 connect(resetButton, SIGNAL(clicked()), this, SLOT(resetStat()));
182 connect(graphButton, SIGNAL(clicked()), this, SLOT(displayGraph()));
183 connect(threadSpinBox, SIGNAL(valueChanged(int)), this, SLOT(threadChanged(int)));
184 connect(hreduxSlider, SIGNAL(valueChanged(int)), this, SLOT(hreduxChanged(int)));
185 connect(queueSlider, SIGNAL(valueChanged(int)), this, SLOT(queueChanged(int)));
186 connect(defaultButton, SIGNAL(clicked()), this, SLOT(defaultConfig()));
187 connect(bforceBox, SIGNAL(currentIndexChanged(int)), this, SLOT(bforceChanged(int)));
188 connect(hideUnameBox, SIGNAL(currentIndexChanged(int)), this, SLOT(hideUnameChanged(int)));
189 connect(auditModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(auditModeChanged(int)));
190 connect(aboutButton, SIGNAL(clicked()), this, SLOT(displayAbout()));
191 connect(helpButton, SIGNAL(clicked()), this, SLOT(displayHelp()));
192 connect(sessBox, SIGNAL(stateChanged(int)), this, SLOT(sessOnOff(int)));
193 connect(sessButton, SIGNAL(clicked()), this, SLOT(chooseSessFile()));
194
195 // Setup a timer which will be used to pool the message queue at
196 // regular intervals.
197
198 QTimer *timer = new QTimer(this);
199 connect(timer, SIGNAL(timeout()), this, SLOT(handleMessages()));
200 timer->start(500);
201
202 // Associtate the tables to the hashes and update the statistics,
203 // status bar and the preferences.
204
205 tablesChanged();
206
207 updateStat();
208 updateStatus();
209 updateConfig();
210
211 // Start cracking if the user asked it.
212
213 if (arg->run)
214 emit startStopCrack();
215 }
216 //---------------------------------------------------------------------------
tableItemChanged(QStandardItem * item)217 void OphcrackGUI::tableItemChanged(QStandardItem *item) {
218 QStandardItem *parent = item->parent();
219 QModelIndex index = tableModel->indexFromItem(item);
220
221 int row = index.row();
222 int col = index.column();
223
224 if (col > 0) return;
225
226 // If it is a top level item, then we refresh all the root items.
227
228 if (parent == 0) {
229 int nrows = tableModel->rowCount();
230
231 for (int i=0; i<nrows; ++i) {
232 QStandardItem *root = tableModel->item(i, 0);
233 int nenabled = root->data(Qt::UserRole).toInt();
234
235 if (nenabled > 0)
236 tableView->setRowHidden(i, QModelIndex(), false);
237 else
238 tableView->setRowHidden(i, QModelIndex(), true);
239 }
240 }
241
242 // If is is a child item, then we refresh only the concerned item.
243
244 else {
245 QModelIndex index = tableModel->indexFromItem(parent);
246 table_t *tbl = tableModel->tableFromItem(item);
247
248 if (tbl && tbl->enabled)
249 tableView->setRowHidden(row, index, false);
250 else
251 tableView->setRowHidden(row, index, true);
252 }
253 }
254 //---------------------------------------------------------------------------
selectTables(void)255 void OphcrackGUI::selectTables(void) {
256 if (tableDialog == 0) {
257 tableDialog = new TableDialog(tableModel, this);
258
259 connect(tableDialog, SIGNAL(install(QString, bool, bool)),
260 this, SLOT(installTables(QString, bool, bool)));
261 }
262
263 if (tableDialog->exec() == QDialog::Accepted) {
264 fsm_reset_preload(fsm);
265 tablesChanged();
266 }
267 }
268 //---------------------------------------------------------------------------
tablesChanged(void)269 void OphcrackGUI::tablesChanged(void) {
270 // Return to the 'start' state and ignore any pending message.
271
272 fsm->oldstate = st_start;
273 list_clear(fsm->pending_msg);
274
275 // Save the table configuration and update the status bar.
276
277 saveConfig();
278 updateStatus();
279
280 // Build a list of the enabled tables following the order specified
281 // by the user.
282
283 list_t *enabled = crack->enabled;
284 list_clear(enabled);
285
286 int nrows = tableModel->rowCount();
287 int i, j;
288
289 for (i=0; i<nrows; ++i) {
290 QStandardItem *item = tableModel->item(i, 0);
291 int ntables = item->rowCount();
292
293 for (j=0; j<ntables; ++j) {
294 QStandardItem *child = item->child(j, 0);
295 table_t *tbl = (table_t*)child->data(Qt::UserRole).value<void*>();
296
297 if (tbl->enabled)
298 list_add_tail(enabled, tbl);
299 }
300 }
301
302 // Associate the enabled tables to the hashes. The tables are
303 // added in the order specified by the user. Since, for a given
304 // hash, some tables might have been searched in already, we have to
305 // be careful to retain the last visited column so that we do not
306 // need to go through the whole table again.
307
308 list_t *hashes = crack->hashes;
309 int maxtid = crack->maxtid;
310
311 list_nd_t *hnd;
312 list_nd_t *tnd;
313
314 htbl_t **id_to_htbl = (htbl_t**)malloc(maxtid*sizeof(htbl_t*));
315
316 for (hnd = hashes->head; hnd != 0; hnd = hnd->next) {
317 hash_t *hsh = (hash_t*)hnd->data;
318
319 // We store the tables associated with the current hash into the
320 // id_to_htbl array so that we can retrieve them easily later. The
321 // column index is reset to its 'covered' (minus one) value so
322 // that we are sure we do not miss a column.
323
324 memset(id_to_htbl, 0, maxtid*sizeof(htbl_t*));
325
326 while (hsh->tables->size > 0) {
327 htbl_t *htbl = (htbl_t*)list_rem_head(hsh->tables);
328 table_t *tbl = htbl->tbl;
329
330 assert(id_to_htbl[tbl->id] == 0);
331
332 id_to_htbl[tbl->id] = htbl;
333 htbl->col = htbl->covered-1;
334 }
335
336 // We associate the tables to the current hash following the order
337 // specified by the user.
338
339 list_t *enabled = crack->enabled;
340
341 for (tnd = enabled->head; tnd != 0; tnd = tnd->next) {
342 table_t *tbl = (table_t*)tnd->data;
343 htbl_t *htbl = id_to_htbl[tbl->id];
344
345 if (htbl != 0) {
346 list_add_tail(hsh->tables, htbl);
347 id_to_htbl[tbl->id] = 0;
348 } else
349 ophcrack_associate(crack, hsh, tbl);
350 }
351
352 // Some tables which were previously associated to the hash might
353 // not have been enabled this time. We store them anyway because
354 // we want to keep track of the last column we have been searching
355 // from.
356
357 int i;
358
359 for (i=0; i<maxtid; ++i) {
360 htbl_t *htbl = id_to_htbl[i];
361
362 if (htbl != 0)
363 list_add_tail(hsh->tables, htbl);
364 }
365
366 // Since we changed the list of tables, we should reset the table
367 // list node pointer.
368
369 hsh->tnd = 0;
370 }
371
372 free(id_to_htbl);
373
374 // Update the status of the search in the tables.
375
376 ophcrack_update(crack);
377 updateProgress();
378 }
379 //---------------------------------------------------------------------------
hashesAdded(list_t * hashes)380 void OphcrackGUI::hashesAdded(list_t *hashes) {
381 list_t *enabled = crack->enabled;
382 list_nd_t *hnd, *tnd;
383
384 for (hnd = hashes->head; hnd != 0; hnd = hnd->next) {
385 hash_t *hsh = (hash_t*)hnd->data;
386
387 assert(hsh->tables->size == 0);
388
389 for (tnd = enabled->head; tnd != 0; tnd = tnd->next) {
390 table_t *tbl = (table_t*)tnd->data;
391 ophcrack_associate(crack, hsh, tbl);
392 }
393 }
394
395 fsm_reset_preload(fsm);
396 fsm_reset_bforce(fsm);
397
398 ophcrack_update(crack);
399 updateProgress();
400 }
401 //---------------------------------------------------------------------------
startStopCrack(void)402 void OphcrackGUI::startStopCrack(void) {
403 int npwds_total = crack->npwds_total;
404 int npwds_found = crack->npwds_found;
405
406 if (fsm->state == st_wait && npwds_found < npwds_total) {
407 startCrack();
408 fsm_reset(fsm);
409
410 fsm->state = st_start;
411 fsm_handle_start(fsm);
412 }
413
414 else if (fsm->state == st_pause1) {
415 if (npwds_found < npwds_total) {
416 startCrack();
417
418 fsm->state = st_pause2;
419 fsm_handle_pause2(fsm, 0);
420 }
421 }
422
423 else if (fsm->state == st_pause2) {
424 stopCrack();
425 fsm->state = st_pause1;
426 }
427
428 else if (fsm->state != st_wait) {
429 stopCrack();
430 fsm_pause(fsm);
431 }
432 }
433 //---------------------------------------------------------------------------
loadSingleHash(void)434 void OphcrackGUI::loadSingleHash(void) {
435 SingleHashDialog singleHashDialog;
436
437 if (singleHashDialog.exec() == QDialog::Accepted) {
438 char *str = strdup(singleHashDialog.getHash());
439
440 list_t *hashes = list_alloc();
441 list_nd_t *nd;
442
443 int maxhid = crack->maxhid;
444 int ret = hash_extract_lmnt(str, hashes, maxhid);
445
446 // If not hashes could be loaded, then we inform the user.
447
448 if (ret == 0) {
449 QMessageBox msgBox(QMessageBox::Warning,
450 "Warning",
451 QString("No hashes could be extracted." ) +
452 QString("Check that you provided valid hashes ") +
453 QString("in one of the three formats allowed."),
454 QMessageBox::Ok);
455 msgBox.exec();
456 }
457
458 // Otherwise, we add the hashes to the list of hashes we must
459 // potentially crack.
460
461 else {
462 for (nd = hashes->head; nd != 0; nd = nd->next) {
463 hash_t *hsh = (hash_t*)nd->data;
464
465 ophcrack_add_hash(crack, hsh);
466 hashModel->insertHash(hsh);
467 }
468
469 hashesAdded(hashes);
470 }
471
472 free(str);
473 list_free(hashes);
474 }
475 }
476 //---------------------------------------------------------------------------
loadHashFile(void)477 void OphcrackGUI::loadHashFile(void) {
478
479 QString fileName = QFileDialog::getOpenFileName(this,
480 tr("Open PWDUMP file"),
481 QString(),
482 QString());
483
484 if (!fileName.isNull()) {
485 const char *fname = fileName.toLatin1().constData();
486
487 // If the file cannot be read, then we warn the user.
488
489 FILE *file = fopen(fname, "r");
490
491 if (file == 0) {
492 QMessageBox msgBox(QMessageBox::Warning,
493 "Warning",
494 QString("Cannot open file %1 for reading.").arg(fname),
495 QMessageBox::Ok);
496 msgBox.exec();
497 }
498
499 // Otherwise, we load all the hashes we find.
500
501 else {
502 list_t *hashes = list_alloc();
503 list_nd_t *nd;
504
505 int maxhid = crack->maxhid;
506 hash_load_pwdump(hashes, file, maxhid);
507
508 for (nd = hashes->head; nd != 0; nd = nd->next) {
509 hash_t *hsh = (hash_t*)nd->data;
510
511 ophcrack_add_hash(crack, hsh);
512 hashModel->insertHash(hsh);
513 }
514
515 hashesAdded(hashes);
516
517 list_free(hashes);
518 fclose(file);
519 }
520 }
521 }
522 //---------------------------------------------------------------------------
loadSamFile(void)523 void OphcrackGUI::loadSamFile(void) {
524
525 QString dir = QFileDialog::getExistingDirectory(this,
526 tr("Select the directory containing the encrypted SAM and SYSTEM files.\n(Usually under C:\\WINDOWS\\system32\\config\\)"),
527 QString(),
528 QFileDialog::ShowDirsOnly);
529
530 if (!dir.isNull()) {
531 list_t *hashes = list_alloc();
532 list_nd_t *nd;
533
534 // Retrieve the hashes from the encrypted SAM.
535
536 int maxhid = crack->maxhid;
537 int npwds = hash_load_sam(hashes, dir.toLatin1().constData(), maxhid);
538 QString buff = 0;
539
540 // Check that something has actually been loaded.
541
542 if (npwds == 0)
543 buff = QString("No proper hashes have been found in the encrypted SAM file in %1.").arg(arg->samdir);
544
545 // Check if the SYSTEM or SAM file could not be found.
546
547 else if (npwds == -1)
548 buff = QString("No SYSTEM file has been found in %1.").arg(arg->samdir);
549
550 else if (npwds == -2)
551 buff = QString("No SAM file has been found in %1.").arg(arg->samdir);
552
553 // Check if there was a problem while reading the SYSTEM or SAM file.
554
555 else if (npwds == -3)
556 buff = QString("A problem occurred while reading the SYSTEM file found in %1.").arg(arg->samdir);
557
558 else if (npwds == -4)
559 buff = QString("A problem occurred while reading the SAM file found in %1.").arg(arg->samdir);
560
561 if (npwds <= 0) {
562 QMessageBox msgBox(QMessageBox::Warning,
563 "Warning",
564 buff,
565 QMessageBox::Ok);
566 msgBox.exec();
567 }
568
569
570 // Add the hashes.
571
572 for (nd = hashes->head; nd != 0; nd = nd->next) {
573 hash_t *hsh = (hash_t*)nd->data;
574
575 ophcrack_add_hash(crack, hsh);
576 hashModel->insertHash(hsh);
577 }
578
579 hashesAdded(hashes);
580 list_free(hashes);
581 }
582 }
583 //---------------------------------------------------------------------------
loadLocalSamSamdump(void)584 void OphcrackGUI::loadLocalSamSamdump(void) {
585 // Retrieve the hashes from the local SAM with samdump2.
586
587 list_t *hashes = list_alloc();
588 list_nd_t *nd;
589
590 // Retrieve the hashes from the encrypted SAM.
591
592 int maxhid = crack->maxhid;
593 int npwds = hash_dump_sam(hashes, maxhid);
594 QString buff = 0;
595
596 // Check that something has actually been loaded.
597
598 if (npwds == 0)
599 buff = QString("No proper hashes have been dumped with samdump2");
600
601 else if (npwds == -1)
602 buff = QString("Error in samdump2: get_live_syskey function");
603
604 else if (npwds == -2)
605 buff = QString("Error in samdump2: get_sam function\n\nMake sure ophcrack is running with administrator rights to perform this action. On Windows Vista and later, right-click on ophcrack icon and select run as administrator.\n\nThis function is not supported on Windows 10 Anniversary update. Use mimikatz (https://github.com/gentilkiwi/mimikatz/releases/) to dump local hashes: mimikatz privilege::debug token::elevate lsadump::sam");
606
607 else if (npwds == -3)
608 buff = QString("Error in samdump2: samdump2 function");
609
610 if (npwds <= 0) {
611 QMessageBox msgBox(QMessageBox::Warning,
612 "Warning",
613 buff,
614 QMessageBox::Ok);
615 msgBox.exec();
616 }
617
618
619 // Add the hashes.
620
621 for (nd = hashes->head; nd != 0; nd = nd->next) {
622 hash_t *hsh = (hash_t*)nd->data;
623
624 ophcrack_add_hash(crack, hsh);
625 hashModel->insertHash(hsh);
626 }
627
628 hashesAdded(hashes);
629 list_free(hashes);
630 }
631 //---------------------------------------------------------------------------
save(void)632 void OphcrackGUI::save(void) {
633 QString fileName;
634
635 // If an output file has already been specified, then we preselect it.
636
637 if (arg->ofname != 0)
638 fileName = QFileDialog::getSaveFileName(this,
639 tr("Save File"),
640 arg->ofname,
641 QString());
642
643 // Otherwise, we preselect the current directory.
644
645 else
646 fileName = QFileDialog::getSaveFileName(this,
647 tr("Save File"),
648 QDir::currentPath(),
649 QString());
650
651 // If the user chose a file, then we use it to store all the hashes
652 // which are currently loaded.
653
654 if (!fileName.isNull()) {
655 const char *fname = fileName.toLatin1().constData();
656
657 // Store the selected file so that we can preselect it later.
658
659 if (arg->ofname != 0) free(arg->ofname);
660 arg->ofname = strdup(fname);
661
662 FILE *file = fopen(fname, "w");
663
664 if (file == 0) {
665 QMessageBox msgBox(QMessageBox::Warning,
666 "Warning",
667 QString("Cannot open file %1 for writing.").arg(fname),
668 QMessageBox::Ok);
669 msgBox.exec();
670 }
671
672 else {
673 scheduler_t *sched = crack->sched;
674 pthread_mutex_t *mutex = sched->mutex;
675
676 pthread_mutex_lock(mutex);
677 ophcrack_save(crack, file, 0, 0);
678 pthread_mutex_unlock(mutex);
679
680 fclose(file);
681 }
682 }
683 }
684 //---------------------------------------------------------------------------
exportCSV(void)685 void OphcrackGUI::exportCSV(void) {
686 QString fileName;
687 int *fields;
688
689 fields = (int*)malloc(13*sizeof(int));
690 if (exportDialog == 0)
691 exportDialog = new ExportDialog(this);
692
693 if (exportDialog->exec() == QDialog::Accepted) {
694 exportDialog->getFields(fields);
695 fileName = QFileDialog::getSaveFileName(this,
696 tr("Export to CSV"),
697 QDir::currentPath(),
698 QString());
699
700 if (!fileName.isNull()) {
701 const char *fname = fileName.toLatin1().constData();
702
703 FILE *file = fopen(fname, "w");
704
705 if (file == 0) {
706 QMessageBox msgBox(QMessageBox::Warning,
707 "Warning",
708 QString("Cannot open file %1 for writing.").arg(fname),
709 QMessageBox::Ok);
710 msgBox.exec();
711 }
712
713 else {
714 scheduler_t *sched = crack->sched;
715 pthread_mutex_t *mutex = sched->mutex;
716
717 pthread_mutex_lock(mutex);
718 ophcrack_export_csv(crack, file, fields,
719 exportDialog->getSeparator(),
720 exportDialog->getQuotes());
721 pthread_mutex_unlock(mutex);
722
723 fclose(file);
724 }
725 }
726
727 }
728 free(fields);
729 }
730 //---------------------------------------------------------------------------
resetStat(void)731 void OphcrackGUI::resetStat(void) {
732 scheduler_t *sched = crack->sched;
733 pthread_mutex_t *mutex = sched->mutex;
734
735 pthread_mutex_lock(mutex);
736 ophstat_reset(crack->stat);
737 pthread_mutex_unlock(mutex);
738
739 resetTime();
740 updateStat();
741 updateStatus();
742 }
743 //---------------------------------------------------------------------------
displayGraph(void)744 void OphcrackGUI::displayGraph(void) {
745 if (graphDialog == 0) {
746 graphDialog = new GraphDialog(this);
747 }
748
749 int tv_sec = (int) tm_total.tv_sec;
750
751 graphDialog->plot(crack->stat, tv_sec);
752 graphDialog->show();
753 }
754 //---------------------------------------------------------------------------
handleMessages(void)755 void OphcrackGUI::handleMessages(void) {
756 message_t *msg = 0;
757
758 int count = 1000;
759 bool flag = false;
760
761 // Handle at most 'count' messages.
762
763 state_t fsm_state = fsm->state;
764
765 while (count-- && (msg = message_tryget())) {
766 // A password has been found.
767
768 if (msg->kind == msg_found) {
769 msg_found_t *found = (msg_found_t*)msg->data;
770 hash_t *hsh = found->hsh;
771
772 int tv_sec = (int) tm_total.tv_sec;
773
774 if (graphDialog != 0 && graphDialog->isVisible())
775 graphDialog->plot(crack->stat, tv_sec);
776 hashModel->updateHash(hsh);
777 }
778
779 // The preloading of a single file is done.
780
781 else if (msg->kind == msg_preload) {
782 msg_load_t *load = (msg_load_t*)msg->data;
783 table_t *tbl = load->tbl;
784
785 if (tbl && load->done)
786 tableModel->updateTable(tbl);
787
788 else if (tbl == 0 && load->size == 0) {
789 for (list_nd_t *nd = crack->enabled->head; nd != 0; nd = nd->next)
790 tableModel->updateTable((table_t*)nd->data);
791 }
792 }
793
794 // A table has been unloaded.
795
796 else if (msg->kind == msg_unload) {
797 msg_load_t *load = (msg_load_t*)msg->data;
798 table_t *tbl = load->tbl;
799
800 if (tbl)
801 tableModel->updateTable(tbl);
802 }
803
804 // Ask the finite state machine to take the appropriate steps
805 // given the received message.
806
807 msg = fsm_next(fsm, msg);
808
809 // Delete the message.
810
811 if (msg)
812 message_free(msg);
813
814 flag = true;
815 }
816
817 if (fsm->state & (~st_wait & ~st_pause1 & ~st_pause2)) {
818 updateStat();
819 updateProgress();
820 updateStatus();
821 }
822
823 else if (flag)
824 updateStatus();
825
826 // Check if it is time to save the session.
827
828 if (arg->ssave && fsm->state & (st_work1 + st_work2)) {
829 struct timeval tm_curr;
830 gettimeofday(&tm_curr, 0);
831
832 time_t tv_sec = tm_curr.tv_sec - tm_sess.tv_sec;
833
834 if (tv_sec >= 30) {
835 tm_sess = tm_curr;
836 fsm_ssave(fsm);
837 }
838 }
839
840 // Check if the job is finished.
841
842 if (fsm->state == st_wait && fsm_state != st_wait) stopCrack();
843 }
844 //---------------------------------------------------------------------------
startCrack(void)845 void OphcrackGUI::startCrack(void) {
846 crackButton->setIcon(QIcon(":/icons/pixmaps/stop.png"));
847 crackButton->setText("Stop");
848
849 loadButton->setEnabled(false);
850 deleteButton->setEnabled(false);
851 tableButton->setEnabled(false);
852 tabWidget->setTabEnabled(2, false);
853
854 gettimeofday(&tm_start, 0);
855 tm_sess = tm_start;
856 extern struct timeval tm_main_start;
857 tm_main_start = tm_start;
858
859 showNotFound(false);
860 }
861 //---------------------------------------------------------------------------
stopCrack(void)862 void OphcrackGUI::stopCrack(void) {
863 crackButton->setIcon(QIcon(":/icons/pixmaps/crack.png"));
864 crackButton->setText("Crack");
865
866 loadButton->setEnabled(true);
867 deleteButton->setEnabled(crack->hashes->size > 0 ? true : false);
868 tableButton->setEnabled(true);
869 tabWidget->setTabEnabled(2, true);
870
871 updateStat();
872 updateStatus();
873 updateProgress();
874
875 if (fsm->state == st_wait) showNotFound(true);
876 }
877 //---------------------------------------------------------------------------
delSelection(void)878 void OphcrackGUI::delSelection(void) {
879 // Check that we are in a state which allow deleting hashes.
880
881 if (fsm->state & (~st_wait & ~st_pause1)) return;
882
883 // Check that some hashes have actually been selected.
884
885 QList<QModelIndex> indexes = hashSelModel->selectedRows();
886
887 if (indexes.isEmpty()) return;
888
889 // Create a map which gives, for a given hash id, the list of hashes
890 // with that id in the order they are stored in the list of hashes
891 // in the ophrack_t data structure.
892
893 QMultiMap<int, hash_t*>hashFromId;
894 list_t *hashes = crack->hashes;
895
896 while (hashes->size > 0) {
897 hash_t *hsh = (hash_t*)list_rem_tail(hashes);
898 hashFromId.insert(hsh->id, hsh);
899 }
900
901 // Delete the selected hashes. If we are in the 1st pause state, it
902 // might not be appropriate to free the memory occupied by a hash
903 // because it might still be used by a running task. In that case,
904 // we store the hashes and they will be removed later, when it will
905 // be safer.
906
907 int maxhid = crack->maxhid;
908
909 while (!indexes.isEmpty()) {
910 QModelIndex index = indexes.takeFirst();
911 int id = index.data(Qt::UserRole).toInt();
912
913 assert(id >= 0 && id < maxhid);
914 QList<hash_t*> hashes = hashFromId.values(id);
915 assert(hashes.size() > 0);
916
917 while (!hashes.isEmpty()) {
918 hash_t *hsh = hashes.takeFirst();
919 hsh->id = -1;
920
921 if (fsm->state == st_pause1)
922 list_add_tail(fsm->htoremove, hsh);
923 else
924 hash_free(hsh);
925 }
926
927 hashFromId.remove(id);
928 }
929
930 // Manually reset the hash related stuff in ophcrack.
931
932 crack->hnd = 0;
933 crack->maxhid = 0;
934 crack->npwds_total = 0;
935 crack->npwds_found = 0;
936 for (int i=0; i<16; i++) {
937 crack->stat->length[i]=0;
938 crack->stat->category[i]=0;
939 }
940 list_clear(crack->stat->time);
941
942 // Remove all the lines in the hash view. Since the number of rows
943 // changes, we always remove the first one.
944
945 int nrows = hashModel->rowCount();
946
947 for (int i=0; i<nrows; ++i)
948 hashModel->removeRow(0);
949
950 // Adjust the id of the remaining hashes and insert them into the
951 // ophcrack_t data structure.
952
953 for (int i=0; i<maxhid; ++i) {
954 QList<hash_t*> hashes = hashFromId.values(i);
955 int j = i;
956
957 while (hashes.isEmpty() && ++j < maxhid)
958 hashes = hashFromId.values(j);
959
960 if (j == maxhid) break;
961 hashFromId.remove(j);
962
963 while (!hashes.isEmpty()) {
964 hash_t *hsh = hashes.takeFirst();
965
966 hsh->id = i;
967 ophcrack_add_hash(crack, hsh);
968 hashModel->insertHash(hsh);
969 }
970 }
971
972 assert(crack->maxhid == crack->npwds_total);
973
974 updateStatus();
975 updateProgress();
976 }
977 //---------------------------------------------------------------------------
updateStat(void)978 void OphcrackGUI::updateStat(void) {
979 scheduler_t *sched = crack->sched;
980 pthread_mutex_t *mutex = sched->mutex;
981 ophstat_t *stat = crack->stat;
982
983 pthread_mutex_lock(mutex);
984 uint64_t hredux = stat->hredux;
985 uint64_t prefix = stat->prefix;
986 uint64_t postfix = stat->postfix;
987 uint64_t start = stat->start;
988 uint64_t fseek_idx = stat->fseek_idx;
989 uint64_t fseek_end = stat->fseek_end;
990 uint64_t fseek_srt = stat->fseek_srt;
991 uint64_t falarm = stat->falarm;
992 uint64_t falarm_hredux = stat->falarm_hredux;
993 uint64_t match_table = stat->match_table;
994 uint64_t match_bforce = stat->match_bforce;
995 pthread_mutex_unlock(mutex);
996
997 // Hash/Redux and false alarms.
998
999 hreduxField->clear();
1000 hreduxField->insert(QString("%1").arg(hredux));
1001
1002 falarmField->clear();
1003 falarmField->insert(QString("%1").arg(falarm));
1004
1005 falarm2Field->clear();
1006
1007 if (falarm > 0)
1008 falarm2Field->insert(QString("%1").arg(falarm_hredux / falarm));
1009 else
1010 falarm2Field->insert(QString("0"));
1011
1012 // Passwords.
1013
1014 pwdField->clear();
1015 pwdField->insert(QString("%1").arg(match_table));
1016
1017 bforceField->clear();
1018 bforceField->insert(QString("%1").arg(match_bforce));
1019
1020 // Fseek.
1021
1022 uint64_t fseek = fseek_idx + fseek_end + fseek_srt;
1023
1024 fseekField->clear();
1025 fseekField->insert(QString("%1").arg(fseek));
1026
1027 idxField->clear();
1028 idxField->insert(QString("%1").arg(fseek_idx));
1029
1030 endField->clear();
1031 endField->insert(QString("%1").arg(fseek_end));
1032
1033 srtField->clear();
1034 srtField->insert(QString("%1").arg(fseek_srt));
1035
1036 // Prefix, postfix and start.
1037
1038 prefixField->clear();
1039 prefixField->insert(QString("%1").arg(prefix));
1040
1041 postfixField->clear();
1042 postfixField->insert(QString("%1").arg(postfix));
1043
1044 startField->clear();
1045 startField->insert(QString("%1").arg(start));
1046
1047 }
1048 //---------------------------------------------------------------------------
updateProgress(void)1049 void OphcrackGUI::updateProgress(void) {
1050 scheduler_t *sched = crack->sched;
1051 pthread_mutex_t *mutex = sched->mutex;
1052
1053 ophcrack_update(crack);
1054
1055 pthread_mutex_lock(mutex);
1056 tableModel->updateProgress();
1057 pthread_mutex_unlock(mutex);
1058 }
1059 //---------------------------------------------------------------------------
updateStatus(void)1060 void OphcrackGUI::updateStatus(void) {
1061 int npwds_total = crack->npwds_total;
1062 int npwds_found = crack->npwds_found;
1063
1064 // Preload progress.
1065
1066 uint64_t psize_curr = fsm->psize_curr;
1067 uint64_t psize_total = fsm->psize_total;
1068 int psize_ratio = 0;
1069
1070 if (psize_total > 0)
1071 psize_ratio = (100*psize_curr) / psize_total;
1072
1073 QString preloadStr = "waiting";
1074
1075 if (psize_ratio == 100)
1076 preloadStr = "done";
1077
1078 else if (psize_total > 0)
1079 preloadStr = QString("%1%").arg(psize_ratio);
1080
1081 preloadEdit->setText(preloadStr);
1082
1083 // Brute force.
1084
1085 if (!arg->bforce)
1086 bforceEdit->setText("disabled");
1087
1088 else {
1089 uint64_t bforce_curr = fsm->bforce_curr;
1090 uint64_t bforce_total = fsm->bforce_total;
1091 int bforce_ratio = 0;
1092
1093 if (bforce_total > 0)
1094 bforce_ratio = (100*bforce_curr) / bforce_total;
1095
1096 QString bforceStr = "waiting";
1097
1098 if (bforce_ratio == 100)
1099 bforceStr = "done";
1100
1101 else if (bforce_total > 0)
1102 bforceStr = QString("%1%").arg(bforce_ratio);
1103
1104 bforceEdit->setText(bforceStr);
1105 }
1106
1107 // Number of passwords found.
1108
1109 QString pwdStr = QString("%1/%2").arg(npwds_found)
1110 .arg(npwds_total);
1111
1112 pwdEdit->setText(pwdStr);
1113
1114 // Elapsed time.
1115
1116 if (fsm->state & (~st_wait & ~st_pause1 & ~st_pause2)) {
1117 struct timeval tm_stop;
1118 extern struct timeval tm_main_total;
1119 gettimeofday(&tm_stop, 0);
1120
1121 tm_total.tv_sec += tm_stop.tv_sec - tm_start.tv_sec;
1122 tm_main_total.tv_sec = tm_total.tv_sec;
1123 tm_start = tm_stop;
1124 }
1125
1126 long tv_sec = tm_total.tv_sec;
1127 long hour = tv_sec / 3600;
1128 long sec = tv_sec - 3600 * hour;
1129 long min = sec / 60;
1130
1131 sec %= 60;
1132
1133 QString tmStr = QString("%1h %2m %3s").arg(hour).arg(min)
1134 .arg(sec);
1135
1136 timeEdit->setText(tmStr);
1137 }
1138 //---------------------------------------------------------------------------
resetTime(void)1139 void OphcrackGUI::resetTime(void) {
1140 tm_start.tv_sec = 0;
1141 tm_start.tv_usec = 0;
1142 tm_total.tv_sec = 0;
1143 tm_total.tv_usec = 0;
1144
1145 if (fsm->state & (~st_wait & ~st_pause1 & ~st_pause2))
1146 gettimeofday(&tm_start, 0);
1147 }
1148 //---------------------------------------------------------------------------
defaultConfig(void)1149 void OphcrackGUI::defaultConfig(void) {
1150 arg_default(arg);
1151 updateConfig();
1152 }
1153 //---------------------------------------------------------------------------
updateConfig(void)1154 void OphcrackGUI::updateConfig(void) {
1155 int nthreads = arg->nthreads;
1156 int nhredux = arg->nhredux;
1157 int mdqueue = arg->mdqueue;
1158 int bforce = arg->bforce;
1159 int hideuname = arg->hideuname;
1160 int auditmode = arg->auditmode;
1161
1162 threadSpinBox->setValue(nthreads);
1163 threadChanged(nthreads);
1164
1165 hreduxSlider->setSliderPosition(nhredux / 5000);
1166 hreduxChanged(nhredux / 5000);
1167
1168 queueSlider->setSliderPosition(mdqueue / 50);
1169 queueChanged(mdqueue / 50);
1170
1171 bforceBox->setCurrentIndex(bforce > 0 ? 1 : 0);
1172
1173 hideUnameBox->setCurrentIndex(hideuname > 0 ? 1 : 0);
1174
1175 auditModeBox->setCurrentIndex(auditmode > 0 ? 1 : 0);
1176
1177 if (arg->sfname != 0) {
1178 sessEdit->setText(arg->sfname);
1179 sessBox->setCheckState(arg->ssave ? Qt::Checked : Qt::Unchecked);
1180 sessBox->setEnabled(true);
1181 }
1182 }
1183 //---------------------------------------------------------------------------
threadChanged(int x)1184 void OphcrackGUI::threadChanged(int x) {
1185 if (x != crack->arg->nthreads) {
1186 arg->nthreads = x;
1187 threadLabel->setText(QString("restart required"));
1188 }
1189 else
1190 threadLabel->setText(QString(""));
1191 }
1192 //---------------------------------------------------------------------------
hreduxChanged(int x)1193 void OphcrackGUI::hreduxChanged(int x) {
1194 arg->nhredux = 5000*x;
1195 hreduxLabel->setText(QString("%1").arg(arg->nhredux));
1196 }
1197 //---------------------------------------------------------------------------
queueChanged(int x)1198 void OphcrackGUI::queueChanged(int x) {
1199 arg->mdqueue = 50*x;
1200 queueLabel->setText(QString("%1").arg(arg->mdqueue));
1201 }
1202 //---------------------------------------------------------------------------
bforceChanged(int x)1203 void OphcrackGUI::bforceChanged(int x) {
1204 arg->bforce = x;
1205
1206 fsm_reset_bforce(fsm);
1207 updateStatus();
1208 }
1209 //---------------------------------------------------------------------------
hideUnameChanged(int x)1210 void OphcrackGUI::hideUnameChanged(int x) {
1211 arg->hideuname = x;
1212
1213 hashModel->setUnameVisible(x);
1214
1215 list_nd_t *nd;
1216 for (nd = crack->hashes->head; nd != 0; nd = nd->next) {
1217 hash_t *hsh = (hash_t*)nd->data;
1218 hashModel->updateHash(hsh);
1219 }
1220
1221 }
1222 //---------------------------------------------------------------------------
auditModeChanged(int x)1223 void OphcrackGUI::auditModeChanged(int x) {
1224 arg->auditmode = x;
1225
1226 hashModel->setAuditMode(x);
1227
1228 list_nd_t *nd;
1229 for (nd = crack->hashes->head; nd != 0; nd = nd->next) {
1230 hash_t *hsh = (hash_t*)nd->data;
1231 hashModel->updateHash(hsh);
1232 }
1233
1234 if (x)
1235 hideUnameBox->setEnabled(false);
1236 else
1237 hideUnameBox->setEnabled(true);
1238 }
1239 //---------------------------------------------------------------------------
saveConfig(void)1240 void OphcrackGUI::saveConfig(void) {
1241 FILE *file = fopen(arg->cfname, "w");
1242
1243 if (file == 0) return;
1244
1245 // Save the order and state (enabled or not) of the tables.
1246
1247 int nrows = tableModel->rowCount();
1248
1249 for (int i=0; i<nrows; ++i) {
1250 QStandardItem *root = tableModel->item(i, 0);
1251 int nenabled = root->data(Qt::UserRole).toInt();
1252 int nchildren = root->rowCount();
1253
1254 if (nenabled == -1) continue;
1255
1256 QStandardItem *child = root->child(0, 0);
1257 table_t *tbl = tableModel->tableFromItem(child);
1258 const char *path = tbl->path;
1259
1260 fprintf(file, "table %s", path);
1261
1262 if (nenabled == 0) {
1263 fprintf(file, ",-\n");
1264 continue;
1265 }
1266
1267 for (int j=0; j<nchildren; ++j) {
1268 child = root->child(j, 0);
1269 tbl = tableModel->tableFromItem(child);
1270
1271 if (tbl->enabled)
1272 fprintf(file, ",%d", tbl->idx);
1273 }
1274
1275 fprintf(file, "\n");
1276 }
1277
1278 // Save the preferences.
1279
1280 fprintf(file, "nthreads %d\n", arg->nthreads);
1281 fprintf(file, "nhredux %d\n", arg->nhredux);
1282 fprintf(file, "maxdqueue %d\n", arg->mdqueue);
1283 fprintf(file, "bforce %d\n", arg->bforce);
1284 fprintf(file, "hideuname %d\n", arg->hideuname);
1285 fprintf(file, "auditmode %d\n", arg->auditmode);
1286
1287 if (arg->sfname != 0) {
1288 fprintf(file, "session_file %s\n", arg->sfname);
1289 fprintf(file, "session_save %d\n", arg->ssave);
1290 }
1291
1292 fclose(file);
1293 }
1294 //---------------------------------------------------------------------------
close(void)1295 void OphcrackGUI::close(void) {
1296 saveConfig();
1297 QMainWindow::close();
1298 }
1299 //---------------------------------------------------------------------------
closeEvent(QCloseEvent * event)1300 void OphcrackGUI::closeEvent(QCloseEvent *event) {
1301 saveConfig();
1302 QMainWindow::closeEvent(event);
1303 }
1304 //---------------------------------------------------------------------------
addDelHash(const QModelIndex &,int,int)1305 void OphcrackGUI::addDelHash(const QModelIndex &, int, int) {
1306 // Disable/enable the save and delete button.
1307
1308 saveButton->setEnabled(crack->hashes->size ? true : false);
1309 deleteButton->setEnabled(crack->hashes->size > 0 ? true : false);
1310 }
1311 //---------------------------------------------------------------------------
displayAbout(void)1312 void OphcrackGUI::displayAbout(void) {
1313 AboutDialog about;
1314 about.exec();
1315 }
1316 //---------------------------------------------------------------------------
displayHelp(void)1317 void OphcrackGUI::displayHelp(void) {
1318 if (helpDialog == 0)
1319 helpDialog = new HelpDialog(this);
1320
1321 helpDialog->show();
1322 }
1323 //---------------------------------------------------------------------------
installTables(QString str,bool replace,bool warn)1324 void OphcrackGUI::installTables(QString str, bool replace, bool warn) {
1325 const char *tblstr = str.toLatin1().constData();
1326
1327 // Search for the tables in the various directories specified.
1328
1329 list_t *table_path = crack->arg->table_path;
1330 list_t *tables = list_alloc();
1331 list_nd_t *dnd;
1332
1333 for (dnd = table_path->head; dnd != 0; dnd = dnd->next) {
1334 char *dir = (char*)dnd->data;
1335 int ret = table_open(tables, dir, tblstr);
1336
1337 if (ret >= 0) break;
1338 }
1339
1340 // If the requested tables were not found, then we notify the user.
1341
1342 if (warn && dnd == 0) {
1343 QMessageBox msgBox(QMessageBox::Warning,
1344 "Warning",
1345 QString("You requested the table(s) %1, ").arg(str) +
1346 QString("but some or all tables could not ") +
1347 QString("be found or loaded."),
1348 QMessageBox::Ok);
1349 msgBox.exec();
1350 }
1351
1352 // If some tables have been loaded, then we install them.
1353
1354 else if (dnd != 0) {
1355 assert(tables->size > 0);
1356
1357 table_t *tbl = (table_t*)tables->head->data;
1358 table_kind_t kind = tbl->kind;
1359
1360 // Check the size of the tables.
1361
1362 int size_invalid = 0;
1363 list_nd_t *nd;
1364
1365 for (nd = tables->head; nd != 0; nd = nd->next) {
1366 table_t *tbl = (table_t*)nd->data;
1367 ophcrack_setup_table(tbl);
1368 if (table_verify(tbl) < 0) {
1369 size_invalid = 1;
1370 QMessageBox msgBox(QMessageBox::Warning,
1371 "Warning",
1372 QString("Size of table %1 is invalid.").arg(str) +
1373 QString("Please download it again."),
1374 QMessageBox::Ok);
1375 msgBox.exec();
1376 }
1377 }
1378
1379 // Check if we must replace existing tables by the newly loaded
1380 // ones.
1381
1382 bool installed = tableModel->isInstalled(kind);
1383
1384 if (replace && installed) {
1385 int ntables = crack->tables->size;
1386 int i;
1387
1388 for (i=0; i<ntables; ++i) {
1389 table_t *tbl = (table_t*)list_rem_head(crack->tables);
1390
1391 if (tbl->kind != kind)
1392 list_add_tail(crack->tables, tbl);
1393 }
1394
1395 tableModel->uninstall(kind);
1396
1397 // Install the newly loaded tables.
1398 if (!size_invalid) {
1399 for (nd = tables->head; nd != 0; nd = nd->next) {
1400 table_t *tbl = (table_t*)nd->data;
1401 ophcrack_add_table(crack, tbl);
1402 }
1403
1404 tableModel->install(tables);
1405 }
1406 }
1407
1408 // If the tables are not installed yet, then we install them. If
1409 // 'replace' is false then we disable all tables.
1410
1411 else if (!installed && !size_invalid) {
1412 for (nd = tables->head; nd != 0; nd = nd->next) {
1413 table_t *tbl = (table_t*)nd->data;
1414
1415 if (!replace) tbl->enabled = 0;
1416 ophcrack_add_table(crack, tbl);
1417 }
1418
1419 tableModel->install(tables);
1420 }
1421 }
1422 }
1423 //---------------------------------------------------------------------------
sessOnOff(int state)1424 void OphcrackGUI::sessOnOff(int state) {
1425 if (state == Qt::Unchecked) {
1426 arg->ssave = 0;
1427 sessEdit->setEnabled(false);
1428 }
1429
1430 else if (state == Qt::Checked) {
1431 arg->ssave = 1;
1432 fsm->ssave = 1;
1433
1434 sessBox->setEnabled(true);
1435 sessEdit->setEnabled(true);
1436 }
1437 }
1438 //---------------------------------------------------------------------------
chooseSessFile(void)1439 void OphcrackGUI::chooseSessFile(void) {
1440 QString fileName;
1441
1442 // If a session file has already been specified, then we preselect it.
1443
1444 if (arg->sfname != 0)
1445 fileName = QFileDialog::getSaveFileName(this,
1446 tr("Choose Session File"),
1447 arg->sfname);
1448
1449 // Otherwise, we preselect the current directory.
1450
1451 else
1452 fileName = QFileDialog::getSaveFileName(this,
1453 tr("Choose Session File"),
1454 QDir::currentPath());
1455
1456 // If the user chose a file, then we use it to store all the hashes
1457 // which are currently loaded.
1458
1459 if (!fileName.isNull()) {
1460 const char *fname = fileName.toLatin1().constData();
1461
1462 if (arg->sfname != 0) free(arg->sfname);
1463 arg->sfname = strdup(fname);
1464
1465 sessEdit->setText(fileName);
1466
1467 // Uncheck and recheck the checkbox in order to trigger a
1468 // stateChanged signal.
1469
1470 sessBox->setCheckState(Qt::Unchecked);
1471 sessBox->setCheckState(Qt::Checked);
1472 }
1473 }
1474 //---------------------------------------------------------------------------
showNotFound(bool flag)1475 void OphcrackGUI::showNotFound(bool flag) {
1476 list_t *hashes = crack->hashes;
1477 list_nd_t *nd;
1478
1479 for (nd = hashes->head; nd != 0; nd = nd->next) {
1480 hash_t *hsh = (hash_t*)nd->data;
1481
1482 if (hsh->done <= 0 && hsh->id >= 0)
1483 hashModel->updateHash(hsh, flag);
1484 }
1485 }
1486