diff --git a/trunk/dlgsearch.cpp b/trunk/dlgsearch.cpp index 2b370c3..8cfa10d 100644 --- a/trunk/dlgsearch.cpp +++ b/trunk/dlgsearch.cpp @@ -1,96 +1,127 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include "dlgsearch.h" #include "ui_dlgsearch.h" #include DlgSearch::DlgSearch(QWidget *parent) : QDialog(parent), ui(new Ui::DlgSearch) { ui->setupUi(this); } DlgSearch::~DlgSearch() { delete ui; } +QList DlgSearch::Keywords() { + return this->keywords; +} + +bool DlgSearch::SearchNodeNames() { + return this->search_nodes; +} + +bool DlgSearch::SearchKeyNames() { + return this->search_keys; +} + +bool DlgSearch::SearchKeyValues() { + return this->search_values; +} + void DlgSearch::changeEvent(QEvent *e) { QDialog::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void DlgSearch::on_BtnCancel_clicked() { this->reject(); } void DlgSearch::on_BtnSearch_clicked() { if(this->ui->EdtValue->text()=="" || (!this->ui->CbAscii->isChecked() && !this->ui->CbUtf16->isChecked() && !this->ui->CbHex->isChecked())) { // No value type specified QMessageBox::critical(this, tr("Error"), tr("Please specify a search value and type!")); return; } if(!this->ui->CbNodeNames->isChecked() && !this->ui->CbKeyNames->isChecked() && !this->ui->CbKeyValues->isChecked()) { // No target specified QMessageBox::critical(this, tr("Error"), tr("Please specify a search target!")); return; } + // Save settings + QString keyword=this->ui->EdtValue->text(); + this->keywords.clear(); + if(this->ui->CbAscii->isChecked()) this->keywords.append(QByteArray(keyword.toAscii())); + if(this->ui->CbUtf16->isChecked()) { + // TODO: .size()*2 will definetly fail sometimes!!!! + this->keywords.append(QByteArray((char*)(keyword.utf16()),keyword.size()*2)); + } + if(this->ui->CbHex->isChecked()) { + // TODO: Convert to hex + } + + this->search_nodes=this->ui->CbNodeNames->isChecked(); + this->search_keys=this->ui->CbKeyNames->isChecked(); + this->search_values=this->ui->CbKeyValues->isChecked(); this->accept(); } void DlgSearch::on_CbAscii_toggled(bool checked) { // It is not possible to search for text and hex if(checked && this->ui->CbHex->isChecked()) this->ui->CbHex->setChecked(false); } void DlgSearch::on_CbUtf16_toggled(bool checked) { // It is not possible to search for text and hex if(checked && this->ui->CbHex->isChecked()) this->ui->CbHex->setChecked(false); } void DlgSearch::on_CbHex_toggled(bool checked) { // It is not possible to search for text and hex if(checked) { this->ui->CbAscii->setChecked(false); this->ui->CbUtf16->setChecked(false); } } diff --git a/trunk/dlgsearch.h b/trunk/dlgsearch.h index cab6f01..e50d348 100644 --- a/trunk/dlgsearch.h +++ b/trunk/dlgsearch.h @@ -1,55 +1,62 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef DLGSEARCH_H #define DLGSEARCH_H #include +#include +#include namespace Ui { class DlgSearch; } class DlgSearch : public QDialog { Q_OBJECT public: explicit DlgSearch(QWidget *parent = 0); ~DlgSearch(); + QList Keywords(); + bool SearchNodeNames(); + bool SearchKeyNames(); + bool SearchKeyValues(); + protected: void changeEvent(QEvent *e); private slots: void on_BtnCancel_clicked(); - void on_BtnSearch_clicked(); - void on_CbAscii_toggled(bool checked); - void on_CbUtf16_toggled(bool checked); - void on_CbHex_toggled(bool checked); -private: + private: Ui::DlgSearch *ui; + QList keywords; + bool search_nodes; + bool search_keys; + bool search_values; }; #endif // DLGSEARCH_H diff --git a/trunk/dlgsearch.ui b/trunk/dlgsearch.ui index fa6db3a..c681bd2 100644 --- a/trunk/dlgsearch.ui +++ b/trunk/dlgsearch.ui @@ -1,140 +1,146 @@ DlgSearch 0 0 400 210 0 0 Search :/icons/resources/fred.png:/icons/resources/fred.png Search value ASCII + + true + UTF16 + + true + Hexadecimal Search for Node names true Key names true Key values true &Cancel Qt::Horizontal 40 20 &Search diff --git a/trunk/fred.pro b/trunk/fred.pro index f22d4b0..828e249 100644 --- a/trunk/fred.pro +++ b/trunk/fred.pro @@ -1,89 +1,91 @@ #******************************************************************************* # fred Copyright (c) 2011 by Gillen Daniel * # * # Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * # with special feautures useful during forensic analysis. * # * # This program is free software: you can redistribute it and/or modify it * # under the terms of the GNU General Public License as published by the Free * # Software Foundation, either version 3 of the License, or (at your option) * # any later version. * # * # This program is distributed in the hope that it will be useful, but WITHOUT * # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * # more details. * # * # You should have received a copy of the GNU General Public License along with * # this program. If not, see . * #******************************************************************************/ system(bash compileinfo.sh > compileinfo.h) QT += core \ gui \ thread \ script \ webkit TARGET = fred TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp \ registrynode.cpp \ registrynodetreemodel.cpp \ registrykey.cpp \ registrykeytablemodel.cpp \ dlgabout.cpp \ dlgkeydetails.cpp \ qhexedit/qhexedit_p.cpp \ qhexedit/qhexedit.cpp \ datainterpreter.cpp \ reporttemplate.cpp \ datareporter.cpp \ datareporterengine.cpp \ registryhive.cpp \ qtscript_types/bytearray.cpp \ qtscript_types/bytearrayprototype.cpp \ qtscript_types/bytearrayiterator.cpp \ dlgreportviewer.cpp \ registrykeytable.cpp \ registrynodetree.cpp \ dlgsearch.cpp \ - threadsearch.cpp + threadsearch.cpp \ + searchresultwidget.cpp HEADERS += mainwindow.h \ registrynode.h \ registrynodetreemodel.h \ registrykey.h \ registrykeytablemodel.h \ dlgabout.h \ dlgkeydetails.h \ qhexedit/qhexedit_p.h \ qhexedit/qhexedit.h \ datainterpreter.h \ reporttemplate.h \ datareporter.h \ datareporterengine.h \ registryhive.h \ qtscript_types/bytearray.h \ qtscript_types/bytearrayprototype.h \ qtscript_types/bytearrayiterator.h \ dlgreportviewer.h \ registrykeytable.h \ registrynodetree.h \ dlgsearch.h \ - threadsearch.h + threadsearch.h \ + searchresultwidget.h FORMS += mainwindow.ui \ dlgabout.ui \ dlgkeydetails.ui \ dlgreportviewer.ui \ dlgsearch.ui LIBS += -lhivex RESOURCES += fred.qrc diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp index fc075ab..6eab4de 100644 --- a/trunk/mainwindow.cpp +++ b/trunk/mainwindow.cpp @@ -1,575 +1,600 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef FRED_REPORT_TEMPLATE_DIR #define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/" #endif #include #include #include #include #include #include #include "mainwindow.h" #include "ui_mainwindow.h" #include "dlgabout.h" #include "dlgkeydetails.h" #include "dlgreportviewer.h" #include "dlgsearch.h" +#include "searchresultwidget.h" #include "compileinfo.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // Initialize private vars this->p_hive=new RegistryHive(this); this->is_hive_open=false; this->p_reg_node_tree_model=NULL; this->p_reg_key_table_model=NULL; + this->p_search_thread=NULL; // Check for ~/.fred config dir this->CheckUserConfigDir(); // Set main window size int cur_screen=QApplication::desktop()->screenNumber(this); int window_width= QApplication::desktop()->availableGeometry(cur_screen).width()*0.5; int window_height= QApplication::desktop()->availableGeometry(cur_screen).height()*0.5; int window_x= (QApplication::desktop()->availableGeometry(cur_screen).width()/2)- (window_width/2); int window_y= (QApplication::desktop()->availableGeometry(cur_screen).height()/2)- (window_height/2); this->setGeometry(window_x, window_y, window_width, window_height); // Create widgets this->p_horizontal_splitter=new QSplitter(); this->p_horizontal_splitter->setOrientation(Qt::Horizontal); this->p_node_tree=new RegistryNodeTree(this->p_horizontal_splitter); this->p_node_tree->setHeaderHidden(true); this->p_vertical_splitter=new QSplitter(this->p_horizontal_splitter); this->p_vertical_splitter->setOrientation(Qt::Vertical); this->p_key_table=new RegistryKeyTable(this->p_vertical_splitter); this->p_tab_widget=new QTabWidget(this->p_vertical_splitter); this->p_horizontal_splitter2=new QSplitter(); this->p_horizontal_splitter2->setOrientation(Qt::Horizontal); this->p_hex_edit_widget=new QWidget(this->p_horizontal_splitter2); this->p_hex_edit_layout=new QVBoxLayout(this->p_hex_edit_widget); this->p_hex_edit_layout->setContentsMargins(0,0,0,0); this->p_hex_edit=new QHexEdit(); this->p_hex_edit->setReadOnly(true); this->p_hex_edit_status_bar=new QLabel(); this->p_data_interpreter=new DataInterpreter(this->p_horizontal_splitter2); // Make sure hex viewer font is monospaced. QFont mono_font("Monospace"); mono_font.setStyleHint(QFont::TypeWriter); this->p_hex_edit->setFont(mono_font); // Add hexedit page to tab_widget this->p_tab_widget->insertTab(0, this->p_horizontal_splitter2, tr("Hex viewer")); // Lay out widgets this->p_hex_edit_layout->addWidget(this->p_hex_edit); this->p_hex_edit_layout->addWidget(this->p_hex_edit_status_bar); this->p_horizontal_splitter2->addWidget(this->p_hex_edit_widget); this->p_horizontal_splitter2->addWidget(this->p_data_interpreter); this->p_vertical_splitter->addWidget(this->p_key_table); this->p_vertical_splitter->addWidget(this->p_tab_widget); this->p_horizontal_splitter->addWidget(this->p_node_tree); this->p_horizontal_splitter->addWidget(this->p_vertical_splitter); // Set stretch factors QSizePolicy node_tree_policy=this->p_node_tree->sizePolicy(); node_tree_policy.setHorizontalStretch(1); node_tree_policy.setVerticalStretch(100); this->p_node_tree->setSizePolicy(node_tree_policy); QSizePolicy vertical_splitter_policy=this->p_vertical_splitter->sizePolicy(); vertical_splitter_policy.setHorizontalStretch(4); vertical_splitter_policy.setVerticalStretch(100); this->p_vertical_splitter->setSizePolicy(vertical_splitter_policy); QSizePolicy key_table_policy=this->p_key_table->sizePolicy(); key_table_policy.setVerticalStretch(5); key_table_policy.setHorizontalStretch(100); this->p_key_table->setSizePolicy(key_table_policy); QSizePolicy tab_widget_policy=this->p_tab_widget->sizePolicy(); tab_widget_policy.setVerticalStretch(2); tab_widget_policy.setHorizontalStretch(200); this->p_tab_widget->setSizePolicy(tab_widget_policy); QSizePolicy hex_edit_widget_policy=this->p_hex_edit_widget->sizePolicy(); hex_edit_widget_policy.setVerticalStretch(2); hex_edit_widget_policy.setHorizontalStretch(200); this->p_hex_edit_widget->setSizePolicy(hex_edit_widget_policy); QSizePolicy data_interpreter_policy=this->p_data_interpreter->sizePolicy(); data_interpreter_policy.setVerticalStretch(2); data_interpreter_policy.setHorizontalStretch(0); this->p_data_interpreter->setSizePolicy(data_interpreter_policy); // Connect signals this->connect(this->p_node_tree, SIGNAL(clicked(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_node_tree, SIGNAL(activated(QModelIndex)), this, SLOT(SlotNodeTreeClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(clicked(QModelIndex)), this, SLOT(SlotKeyTableClicked(QModelIndex))); this->connect(this->p_key_table, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(SlotKeyTableDoubleClicked(QModelIndex))); this->connect(this->p_hex_edit, SIGNAL(currentAddressChanged(int)), this, SLOT(SlotHexEditAddressChanged(int))); // Add central widget this->setContentsMargins(4,4,4,0); this->setCentralWidget(this->p_horizontal_splitter); // Set window title this->UpdateWindowTitle(); // Set last open location to home dir this->last_open_location=QDir::homePath(); // Load report templates and update menu this->p_data_reporter=new DataReporter(); // Load reports from system wide include dir this->p_data_reporter->LoadReportTemplates(FRED_REPORT_TEMPLATE_DIR); // Load user's report templates this->p_data_reporter->LoadReportTemplates(QDir::homePath() .append(QDir::separator()) .append(".fred") .append(QDir::separator()) .append("report_templates")); this->UpdateDataReporterMenu(); // Finally, parse command line arguments this->ParseCommandLineArgs(); } MainWindow::~MainWindow() { if(this->is_hive_open) { this->p_hive->Close(); } delete ui; } void MainWindow::on_action_Quit_triggered() { qApp->exit(); } void MainWindow::on_action_Open_hive_triggered() { QString hive_file=""; hive_file=QFileDialog::getOpenFileName(this, tr("Open registry hive"), this->last_open_location, tr("All files (*)")); if(hive_file=="") return; this->OpenHive(hive_file); } void MainWindow::on_action_Close_hive_triggered() { if(this->is_hive_open) { // Delete models if(this->p_reg_node_tree_model!=NULL) { this->p_node_tree->setModel(NULL); delete this->p_reg_node_tree_model; this->p_reg_node_tree_model=NULL; } if(this->p_reg_key_table_model!=NULL) { this->p_key_table->setModel(NULL); delete this->p_reg_key_table_model; this->p_reg_key_table_model=NULL; } // Remove any data from hex edit and data interpreter this->p_hex_edit->setData(QByteArray()); this->p_hex_edit_status_bar->setText(""); this->p_data_interpreter->ClearValues(); // Close hive this->p_hive->Close(); this->is_hive_open=false; this->ui->action_Close_hive->setEnabled(false); this->ui->ActionSearch->setEnabled(false); this->ui->MenuReports->setEnabled(false); this->UpdateWindowTitle(); } } void MainWindow::on_actionAbout_Qt_triggered() { QMessageBox::aboutQt(this,tr("About Qt")); } void MainWindow::on_actionAbout_fred_triggered() { DlgAbout dlg_about(this); dlg_about.exec(); } +void MainWindow::on_ActionSearch_triggered() { + DlgSearch dlg_search(this); + if(dlg_search.exec()==QDialog::Accepted) { + // Create search thread and connect needed signals/slots + this->p_search_thread=new ThreadSearch(this); + QList keywords; + keywords.append(QByteArray(QString("Windows").toAscii())); + + // Add new search widget to tabwidget + SearchResultWidget *p_search_widget= + new SearchResultWidget(this->p_tab_widget); + this->p_tab_widget->addTab(p_search_widget,tr("Search results")); + this->p_tab_widget->setCurrentIndex(this->p_tab_widget->count()-1); + + // Connect search thread to result widget + this->connect(this->p_search_thread, + SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType, + QString,QString,QString)), + p_search_widget, + SLOT(SlotFoundMatch(ThreadSearch::eMatchType, + QString,QString,QString))); + this->connect(this->p_search_thread, + SIGNAL(finished()), + this, + SLOT(SlotSearchFinished())); + this->connect(this->p_search_thread, + SIGNAL(finished()), + p_search_widget, + SLOT(SlotSearchFinished())); + + // Start searching + this->ui->ActionSearch->setEnabled(false); + p_search_thread->Search(this->p_hive->Filename(), + dlg_search.Keywords(), + dlg_search.SearchNodeNames(), + dlg_search.SearchKeyNames(), + dlg_search.SearchKeyValues()); + } +} + void MainWindow::SlotNodeTreeClicked(QModelIndex index) { QString node_path; if(!index.isValid()) return; //Built node path node_path.clear(); node_path=this->p_reg_node_tree_model->data(index,Qt::DisplayRole) .toString().prepend("\\"); while(this->p_reg_node_tree_model->parent(index)!=QModelIndex()) { // Prepend all parent nodes index=this->p_reg_node_tree_model->parent(index); node_path.prepend(this->p_reg_node_tree_model->data(index,Qt::DisplayRole) .toString().prepend("\\")); } // Create table model and attach it to the table view if(this->p_reg_key_table_model!=NULL) { this->p_key_table->setModel(NULL); delete this->p_reg_key_table_model; this->p_hex_edit->setData(QByteArray()); this->p_hex_edit_status_bar->setText(""); this->p_data_interpreter->ClearValues(); } this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path); this->p_key_table->setModel(this->p_reg_key_table_model); } void MainWindow::SlotKeyTableDoubleClicked(QModelIndex index) { Q_UNUSED(index); /* QModelIndex key_index; QModelIndex node_index; QStringList nodes; QString key_name; QString key_type; QByteArray key_value; if(!index.isValid()) return; // Get key name, type and value key_index=this->p_reg_key_table_model->index(index.row(),0); key_name=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole) .toString(); key_index=this->p_reg_key_table_model->index(index.row(),1); key_type=this->p_reg_key_table_model->data(key_index,Qt::DisplayRole) - .toString(); + .toString();ThreadSearch key_index=this->p_reg_key_table_model->index(index.row(),2); key_value=this->p_reg_key_table_model->data(key_index, RegistryKeyTableModel:: AdditionalRoles_GetRawData) .toByteArray(); // Get current node node_index=this->p_node_tree->currentIndex(); //Built node path nodes.clear(); nodes.append(this->p_reg_node_tree_model-> data(node_index,Qt::DisplayRole).toString()); while(this->p_reg_node_tree_model->parent(node_index)!=QModelIndex()) { // Prepend all parent nodes node_index=this->p_reg_node_tree_model->parent(node_index); nodes.prepend(this->p_reg_node_tree_model-> data(node_index,Qt::DisplayRole).toString()); } DlgKeyDetails dlg_key_details(this); dlg_key_details.SetValues(nodes,key_name,key_type,key_value); dlg_key_details.exec(); */ } void MainWindow::SlotKeyTableClicked(QModelIndex index) { if(!index.isValid()) return; this->selected_key_value= this->p_reg_key_table_model->data(this->p_reg_key_table_model-> index(index.row(),2), RegistryKeyTableModel:: AdditionalRoles_GetRawData) .toByteArray(); this->p_hex_edit->setData(this->selected_key_value); } void MainWindow::SlotHexEditAddressChanged(int hex_offset) { if(!this->is_hive_open || this->selected_key_value.isEmpty()) return; // Update hex edit status bar this->p_hex_edit_status_bar-> setText(QString().sprintf("Byte offset: 0x%04X (%u)",hex_offset,hex_offset)); // Update data interpreter this->UpdateDataInterpreter(hex_offset); } void MainWindow::SlotReportClicked() { // Get report category and name from sender and it's parent QString category=((QMenu*)((QAction*)QObject::sender())->parent())->title(); QString report=((QAction*)QObject::sender())->text(); // Generate report QString report_content=this->p_data_reporter->GenerateReport(this->p_hive, category, report); // Show result in report viewer if(report_content!=QString()) { DlgReportViewer *p_dlg_report_view=new DlgReportViewer(report_content,this); p_dlg_report_view->exec(); delete p_dlg_report_view; } else { // TODO: Something went wrong! } } -void MainWindow::SlotFoundMatch(ThreadSearch::eMatchType match_type, - QString path, - QString key, - QString value) -{ - qDebug("Found match: path='%s'",path.toAscii().constData()); +void MainWindow::SlotSearchFinished() { + delete this->p_search_thread; + this->p_search_thread=NULL; + this->ui->ActionSearch->setEnabled(true); } void MainWindow::CheckUserConfigDir() { QString user_config_dir=QDir::homePath() .append(QDir::separator()) .append(".fred"); if(!QDir(user_config_dir).exists()) { // User config dir does not exists, try to create it if(!QDir().mkpath(user_config_dir)) { // TODO: Maybe warn user return; } user_config_dir.append(QDir::separator()).append("report_templates"); if(!QDir().mkpath(user_config_dir)) { // TODO: Maybe warn user return; } } } void MainWindow::UpdateWindowTitle(QString filename) { if(filename=="") { this->setWindowTitle(QString().sprintf("%s v%s",APP_TITLE,APP_VERSION)); } else { this->setWindowTitle(QString().sprintf("%s v%s - %s", APP_TITLE, APP_VERSION, filename.toLocal8Bit().constData())); } } void MainWindow::UpdateDataInterpreter(int hex_offset) { QDateTime date_time; const char *p_data; int remaining_data_len; // Remove all old values from data interpreter this->p_data_interpreter->ClearValues(); // Calculate how many bytes are remainig after current offset remaining_data_len=this->selected_key_value.size()-hex_offset; if(!remaining_data_len>0) { // Nothing to show return; } // Get pointer to data at current offset p_data=this->selected_key_value.constData(); p_data+=hex_offset; //#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) //#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) //#define rotl64(x,n) (((x) << n) | ((x) >> (64 - n))) //#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n))) if(remaining_data_len>=1) { this->p_data_interpreter->AddValue("int8:", RegistryHive::KeyValueToString( this->selected_key_value, "int8", hex_offset)); this->p_data_interpreter->AddValue("uint8:", RegistryHive::KeyValueToString( this->selected_key_value, "uint8", hex_offset)); } if(remaining_data_len>=2) { this->p_data_interpreter->AddValue("int16:", RegistryHive::KeyValueToString( this->selected_key_value, "int16", hex_offset)); this->p_data_interpreter->AddValue("uint16:", RegistryHive::KeyValueToString( this->selected_key_value, "uint16", hex_offset)); } if(remaining_data_len>=4) { this->p_data_interpreter->AddValue("int32:", RegistryHive::KeyValueToString( this->selected_key_value, "int32", hex_offset)); this->p_data_interpreter->AddValue("uint32:", RegistryHive::KeyValueToString( this->selected_key_value, "uint32", hex_offset)); this->p_data_interpreter->AddValue("unixtime:", RegistryHive::KeyValueToString( this->selected_key_value, "unixtime", hex_offset)); } if(remaining_data_len>=8) { this->p_data_interpreter->AddValue("int64:", RegistryHive::KeyValueToString( this->selected_key_value, "int64", hex_offset)); this->p_data_interpreter->AddValue("uint64:", RegistryHive::KeyValueToString( this->selected_key_value, "uint64", hex_offset)); this->p_data_interpreter->AddValue("filetime64:", RegistryHive::KeyValueToString( this->selected_key_value, "filetime", hex_offset)); } //#undef rotl32 //#undef rotl64 } void MainWindow::UpdateDataReporterMenu() { int i=0,ii=0; QMenu *p_category_entry; QAction *p_report_entry; - QStringList categories=this->p_data_reporter->GetAvailableReportCategories(); QStringList reports; for(i=0;iui->MenuReports->addMenu(categories.value(i)); // Now add category reports reports=this->p_data_reporter->GetAvailableReports(categories.value(i)); for(ii=0;iiaddAction(p_report_entry); this->connect(p_report_entry, SIGNAL(triggered()), this, SLOT(SlotReportClicked())); } } } void MainWindow::OpenHive(QString hive_file) { // Update last open location this->last_open_location=hive_file.left(hive_file. lastIndexOf(QDir::separator())); // If another hive is currently open, close it if(this->is_hive_open) this->on_action_Close_hive_triggered(); // Try to open hive if(!this->p_hive->Open(hive_file)) { QMessageBox::critical(this, tr("Error opening hive file"), tr("Unable to open file '%1'").arg(hive_file)); return; } // Create tree model this->p_reg_node_tree_model= new RegistryNodeTreeModel(this->p_hive); this->p_node_tree->setModel(this->p_reg_node_tree_model); this->is_hive_open=true; this->ui->action_Close_hive->setEnabled(true); this->ui->ActionSearch->setEnabled(true); this->ui->MenuReports->setEnabled(true); this->UpdateWindowTitle(hive_file); } void MainWindow::ParseCommandLineArgs() { QStringList args=qApp->arguments(); // If exactly 1 argument was specified, it should be a hive to open if(args.count()==2) { this->OpenHive(args.at(1)); } } - -void MainWindow::on_ActionSearch_triggered() { - DlgSearch dlg_search(this); - if(dlg_search.exec()==QDialog::Accepted) { - ThreadSearch *p_search_thread=new ThreadSearch(this); - this->connect(p_search_thread, - SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType,QString,QString,QString)), - this, - SLOT(SlotFoundMatch(ThreadSearch::eMatchType,QString,QString,QString))); - QList keywords; - keywords.append(QByteArray(QString("Windows").toAscii())); - p_search_thread->Search(this->p_hive->Filename(),keywords,true,false,false); - } -} diff --git a/trunk/mainwindow.h b/trunk/mainwindow.h index f5f294b..2723780 100644 --- a/trunk/mainwindow.h +++ b/trunk/mainwindow.h @@ -1,137 +1,133 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include #include #include #include "registryhive.h" #include "registrynodetree.h" #include "registrynodetreemodel.h" #include "registrykeytable.h" #include "registrykeytablemodel.h" #include "qhexedit/qhexedit.h" #include "datainterpreter.h" #include "datareporter.h" #include "threadsearch.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_action_Quit_triggered(); void on_action_Open_hive_triggered(); void on_action_Close_hive_triggered(); void on_actionAbout_Qt_triggered(); void on_actionAbout_fred_triggered(); + void on_ActionSearch_triggered(); void SlotNodeTreeClicked(QModelIndex index); void SlotKeyTableClicked(QModelIndex index); void SlotKeyTableDoubleClicked(QModelIndex index); void SlotHexEditAddressChanged(int hex_offset); void SlotReportClicked(); - void SlotFoundMatch(ThreadSearch::eMatchType match_type, - QString path, - QString key, - QString value); - - void on_ActionSearch_triggered(); + void SlotSearchFinished(); private: Ui::MainWindow *ui; QString last_open_location; RegistryHive *p_hive; bool is_hive_open; RegistryNodeTreeModel *p_reg_node_tree_model; RegistryKeyTableModel *p_reg_key_table_model; QByteArray selected_key_value; // Widgets etc... RegistryNodeTree *p_node_tree; RegistryKeyTable *p_key_table; QTabWidget *p_tab_widget; QWidget *p_hex_edit_widget; QHexEdit *p_hex_edit; QLabel *p_hex_edit_status_bar; DataInterpreter *p_data_interpreter; QVBoxLayout *p_hex_edit_layout; QSplitter *p_horizontal_splitter; QSplitter *p_horizontal_splitter2; QSplitter *p_vertical_splitter; - DataReporter *p_data_reporter; + ThreadSearch *p_search_thread; /* * CheckUserConfigDir * * Checks for and possibly creates the ~/.fred directory */ void CheckUserConfigDir(); /* * UpdateWindowTitle * * Updates the window title */ void UpdateWindowTitle(QString filename=""); /* * UpdateDataInterpreter * * Update data interpreter */ void UpdateDataInterpreter(int hex_offset); /* * UpdateDataReporterMenu * */ void UpdateDataReporterMenu(); /* * OpenHive * * Open a registry hive */ void OpenHive(QString hive_file); /* * ParseCommandLineArgs * * Parse command line arguments */ void ParseCommandLineArgs(); }; #endif // MAINWINDOW_H diff --git a/trunk/searchresultwidget.cpp b/trunk/searchresultwidget.cpp new file mode 100644 index 0000000..a73b986 --- /dev/null +++ b/trunk/searchresultwidget.cpp @@ -0,0 +1,100 @@ +/******************************************************************************* +* fred Copyright (c) 2011 by Gillen Daniel * +* * +* Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * +* with special feautures useful during forensic analysis. * +* * +* This program is free software: you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the Free * +* Software Foundation, either version 3 of the License, or (at your option) * +* any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along with * +* this program. If not, see . * +*******************************************************************************/ + +#include "searchresultwidget.h" + +#include +#include +#include +#include +#include + +SearchResultWidget::SearchResultWidget(QWidget *p_parent) + : QTableWidget(p_parent) +{ + this->setColumnCount(3); + this->setRowCount(0); + this->setTextElideMode(Qt::ElideNone); + this->verticalHeader()->setHidden(true); + this->setSelectionBehavior(QAbstractItemView::SelectRows); + this->setSelectionMode(QAbstractItemView::SingleSelection); + this->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + this->setHorizontalHeaderLabels(QStringList()<rowCount(); + this->setRowCount(rows+1); + p_item=new QTableWidgetItem(full_path=="" ? "\\" : full_path); + this->setItem(rows,0,p_item); + p_item=new QTableWidgetItem(type); + this->setItem(rows,1,p_item); + p_item=new QTableWidgetItem(match); + this->setItem(rows,2,p_item); +} + +int SearchResultWidget::sizeHintForColumn(int column) const { + int size_hint=0; + int i=0; + int item_width=0; + QFontMetrics fm(this->fontMetrics()); + + // Find string that needs the most amount of space + for(i=0;irowCount();i++) { + item_width=fm.width(this->item(i,column)->text())+10; + if(item_width>size_hint) size_hint=item_width; + } + + return size_hint; +} + +void SearchResultWidget::SlotSearchFinished() { + this->resizeColumnsToContents(); +} diff --git a/trunk/dlgsearch.h b/trunk/searchresultwidget.h similarity index 75% copy from trunk/dlgsearch.h copy to trunk/searchresultwidget.h index cab6f01..4dab7f3 100644 --- a/trunk/dlgsearch.h +++ b/trunk/searchresultwidget.h @@ -1,55 +1,45 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ -#ifndef DLGSEARCH_H -#define DLGSEARCH_H +#ifndef SEARCHRESULTWIDGET_H +#define SEARCHRESULTWIDGET_H -#include +#include -namespace Ui { - class DlgSearch; -} +#include "threadsearch.h" -class DlgSearch : public QDialog { +class SearchResultWidget : public QTableWidget { Q_OBJECT public: - explicit DlgSearch(QWidget *parent = 0); - ~DlgSearch(); + SearchResultWidget(QWidget *p_parent=0); - protected: - void changeEvent(QEvent *e); - - private slots: - void on_BtnCancel_clicked(); - - void on_BtnSearch_clicked(); - - void on_CbAscii_toggled(bool checked); + public slots: + void SlotFoundMatch(ThreadSearch::eMatchType match_type, + QString path, + QString key, + QString value); + void SlotSearchFinished(); - void on_CbUtf16_toggled(bool checked); - - void on_CbHex_toggled(bool checked); - -private: - Ui::DlgSearch *ui; + protected: + int sizeHintForColumn(int column) const; }; -#endif // DLGSEARCH_H +#endif // SEARCHRESULTWIDGET_H diff --git a/trunk/threadsearch.cpp b/trunk/threadsearch.cpp index 2b7d6d4..9259746 100644 --- a/trunk/threadsearch.cpp +++ b/trunk/threadsearch.cpp @@ -1,120 +1,190 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #include "threadsearch.h" #include +#include ThreadSearch::ThreadSearch(QObject *p_parent) : QThread(p_parent) { this->hive_file=""; this->h_hive=NULL; this->keywords=QList(); this->search_nodes=false; this->search_keys=false; this->search_values=false; this->root_node=0; + + // Register meta types to be used in signals + qRegisterMetaType("ThreadSearch::eMatchType"); } bool ThreadSearch::Search(QString registry_hive, QList search_keywords, bool search_node_names, bool search_key_names, bool search_key_values, QString search_path) { this->hive_file=registry_hive; this->keywords=search_keywords; this->search_nodes=search_node_names; this->search_keys=search_key_names; this->search_values=search_key_values; - this->root_path=search_path; + this->root_path=search_path=="\\" ? "" : search_path; // Try to open hive this->h_hive=hivex_open(this->hive_file.toAscii().constData(),0); if(this->h_hive==NULL) return false; // Get root node this->root_node=hivex_root(this->h_hive); if(this->root_node==0) { hivex_close(this->h_hive); return false; } // If a root path was specified, iterate to it if(search_path!="\\") { QStringList path_nodes=search_path.split("\\",QString::SkipEmptyParts); int i; for(i=0;iroot_node=hivex_node_get_child(this->h_hive, this->root_node, path_nodes.at(i).toAscii().constData()); if(this->root_node==0) { hivex_close(this->h_hive); return false; } } } this->start(); return true; } void ThreadSearch::run() { qDebug("Starting search"); - this->Match(this->root_node,this->root_path=="\\" ? "" : this->root_path); + this->Match(); qDebug("Ending search"); hivex_close(this->h_hive); } -void ThreadSearch::Match(hive_node_h node, QString path) { +void ThreadSearch::Match(QString path, hive_node_h node) { char *p_node_name; - int i; + int i,ii; hive_node_h *p_node_childs; QByteArray *p_byte_array; //qDebug("Searching in '%s'",path.toAscii().constData()); - p_node_name=hivex_node_name(this->h_hive,node); - if(p_node_name==NULL) return; - - if(this->search_nodes) { - // Compare node name with keywords - p_byte_array=new QByteArray(p_node_name); - for(i=0;ikeywords.count();i++) { - if(p_byte_array->indexOf(this->keywords.at(i))!=-1) { - emit(SIGNAL(SignalFoundMatch(ThreadSearch::eMatchType_NodeName, - path, - QString(p_node_name), - QString()))); + if(node!=0) { + p_node_name=hivex_node_name(this->h_hive,node); + if(p_node_name==NULL) return; + + if(this->search_nodes) { + // Compare node name to keywords + p_byte_array=new QByteArray(p_node_name); + for(i=0;ikeywords.count();i++) { + if(p_byte_array->indexOf(this->keywords.at(i))!=-1) { + emit(SignalFoundMatch(ThreadSearch::eMatchType_NodeName, + path, + QString(p_node_name), + QString())); + } } + delete p_byte_array; } - delete p_byte_array; - } - p_node_childs=hivex_node_children(this->h_hive,node); - if(p_node_childs!=NULL) { - for(i=0;p_node_childs[i];i++) { - this->Match(p_node_childs[i], - QString(path).append("\\").append(p_node_name)); + if(this->search_keys || this->search_values) { + // Get key,value pairs for current node + hive_value_h *p_keys=hivex_node_values(this->h_hive,node); + if(p_keys==NULL) { + delete p_node_name; + return; + } + + if(this->search_keys) { + // Compare key names to keywords + char *p_keyname; + for(i=0;p_keys[i];i++) { + p_keyname=hivex_value_key(this->h_hive,p_keys[i]); + if(p_keyname==NULL) continue; + p_byte_array=new QByteArray(p_keyname); + for(ii=0;iikeywords.count();ii++) { + if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) { + emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyName, + path.append("\\").append(p_node_name), + QString(p_keyname), + QString())); + } + } + delete p_byte_array; + delete p_keyname; + } + } + if(this->search_values) { + // Compare key values to keywords + char *p_value; + hive_type val_type; + size_t val_len; + + for(i=0;p_keys[i];i++) { + p_value=hivex_value_value(this->h_hive,p_keys[i],&val_type,&val_len); + if(p_value==NULL) continue; + p_byte_array=new QByteArray(p_value,val_len); + for(ii=0;iikeywords.count();ii++) { + if(p_byte_array->indexOf(this->keywords.at(ii))!=-1) { + char *p_keyname=hivex_value_key(this->h_hive,p_keys[i]); + if(p_keyname==NULL) continue; + emit(SignalFoundMatch(ThreadSearch::eMatchType_KeyValue, + path.append("\\").append(p_node_name), + QString(p_keyname), + QString())); + delete p_keyname; + } + } + delete p_byte_array; + delete p_value; + } + + } + delete p_keys; + } + + // Search in subnodes + p_node_childs=hivex_node_children(this->h_hive,node); + if(p_node_childs!=NULL) { + for(i=0;p_node_childs[i];i++) { + this->Match(QString(path).append("\\").append(p_node_name), + p_node_childs[i]); + } + delete p_node_childs; + } + delete p_node_name; + } else { + p_node_childs=hivex_node_children(this->h_hive,this->root_node); + if(p_node_childs!=NULL) { + for(i=0;p_node_childs[i];i++) this->Match(this->root_path, + p_node_childs[i]); + delete p_node_childs; } - delete p_node_childs; } - delete p_node_name; } diff --git a/trunk/threadsearch.h b/trunk/threadsearch.h index 4686678..a47a3e3 100644 --- a/trunk/threadsearch.h +++ b/trunk/threadsearch.h @@ -1,75 +1,73 @@ /******************************************************************************* * fred Copyright (c) 2011 by Gillen Daniel * * * * Forensic Registry EDitor (fred) is a cross-platform M$ registry hive editor * * with special feautures useful during forensic analysis. * * * * This program is free software: you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the Free * * Software Foundation, either version 3 of the License, or (at your option) * * any later version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * * more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * *******************************************************************************/ #ifndef THREADSEARCH_H #define THREADSEARCH_H #include #include #include #include #include #include class ThreadSearch : public QThread { Q_OBJECT public: enum eMatchType { eMatchType_NodeName=0, eMatchType_KeyName, eMatchType_KeyValue }; ThreadSearch(QObject *p_parent=0); bool Search(QString registry_hive, QList search_keywords, bool search_node_names, bool search_key_names, bool search_key_values, QString search_path="\\"); signals: void SignalFoundMatch(ThreadSearch::eMatchType match_type, QString path, QString key, QString value); protected: void run(); private: QString hive_file; hive_h *h_hive; QList keywords; bool search_nodes; bool search_keys; bool search_values; QString root_path; hive_node_h root_node; - void Match(hive_node_h node, QString path); + void Match(QString path="", hive_node_h node=0); }; -//Q_DECLARE_TYPEINFO(ThreadSearch::eMatchType,Q_PRIMITIVE_TYPE); - #endif // THREADSEARCH_H