diff --git a/trunk/datainterpreter.cpp b/trunk/datainterpretertable.cpp similarity index 89% rename from trunk/datainterpreter.cpp rename to trunk/datainterpretertable.cpp index 7ea8375..3af93b9 100644 --- a/trunk/datainterpreter.cpp +++ b/trunk/datainterpretertable.cpp @@ -1,111 +1,111 @@ /******************************************************************************* * fred Copyright (c) 2011-2012 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 "datainterpreter.h" +#include "datainterpretertable.h" #include #include #include #include #include -DataInterpreter::DataInterpreter(QWidget *p_parent) +DataInterpreterTable::DataInterpreterTable(QWidget *p_parent) : QTableWidget(p_parent) { this->setColumnCount(2); this->setTextElideMode(Qt::ElideNone); this->horizontalHeader()->setHidden(true); this->verticalHeader()->setHidden(true); this->setSelectionBehavior(QAbstractItemView::SelectRows); this->setSelectionMode(QAbstractItemView::SingleSelection); // Create context menu actions this->p_action_copy_value=new QAction(tr("Copy value"),this); this->connect(this->p_action_copy_value, SIGNAL(triggered()), this, SLOT(SlotCopyValue())); } -DataInterpreter::~DataInterpreter() { +DataInterpreterTable::~DataInterpreterTable() { // Free table widget items this->ClearValues(); // Delete context menu actions delete this->p_action_copy_value; } -void DataInterpreter::AddValue(QString name, QString value) { +void DataInterpreterTable::AddValue(QString name, QString value) { QTableWidgetItem *p_name_item=new QTableWidgetItem(name); p_name_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QTableWidgetItem *p_value_item=new QTableWidgetItem(value); p_value_item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); this->setRowCount(this->rowCount()+1); this->setItem(this->rowCount()-1,0,p_name_item); this->setItem(this->rowCount()-1,1,p_value_item); this->resizeColumnsToContents(); this->resizeRowsToContents(); } -void DataInterpreter::ClearValues() { +void DataInterpreterTable::ClearValues() { // Free all items while(this->rowCount()>0) { delete this->item(0,0); delete this->item(0,1); this->setRowCount(this->rowCount()-1); } } -int DataInterpreter::sizeHintForColumn(int column) const { +int DataInterpreterTable::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 DataInterpreter::contextMenuEvent(QContextMenuEvent *p_event) { +void DataInterpreterTable::contextMenuEvent(QContextMenuEvent *p_event) { // Only show context menu when a node is selected if(this->selectedIndexes().count()!=2) return; // Only show context menu when user clicked on selected row if(!(this->indexAt(p_event->pos())==this->selectedIndexes().at(0) || this->indexAt(p_event->pos())==this->selectedIndexes().at(1))) { return; } // Create context menu and add actions QMenu context_menu(this); context_menu.addAction(this->p_action_copy_value); context_menu.exec(p_event->globalPos()); } -void DataInterpreter::SlotCopyValue() { +void DataInterpreterTable::SlotCopyValue() { QApplication::clipboard()-> setText(this->selectedIndexes().at(1).data().toString(), QClipboard::Clipboard); } diff --git a/trunk/datainterpreter.h b/trunk/datainterpretertable.h similarity index 91% copy from trunk/datainterpreter.h copy to trunk/datainterpretertable.h index d1ee0a3..891fccd 100644 --- a/trunk/datainterpreter.h +++ b/trunk/datainterpretertable.h @@ -1,68 +1,68 @@ /******************************************************************************* * fred Copyright (c) 2011-2012 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 DATAINTERPRETER_H -#define DATAINTERPRETER_H +#ifndef DATAINTERPRETERTABLE_H +#define DATAINTERPRETERTABLE_H #include #include #include #include -class DataInterpreter : public QTableWidget { +class DataInterpreterTable : public QTableWidget { Q_OBJECT public: - DataInterpreter(QWidget *p_parent=0); - ~DataInterpreter(); + DataInterpreterTable(QWidget *p_parent=0); + ~DataInterpreterTable(); /* * AddValue * * Add a value pair (name,value) to data interprter. */ void AddValue(QString name, QString value); /* * ClearValues * * Remove all value pairs from table */ void ClearValues(); protected: /* * sizeHintForColumn * * Needed reimplementation in order to allow resizeColumnsToContent * to resize hidden columns too. */ int sizeHintForColumn(int column) const; void contextMenuEvent(QContextMenuEvent *p_event); private: QAction *p_action_copy_value; private slots: void SlotCopyValue(); }; -#endif // DATAINTERPRETER_H +#endif // DATAINTERPRETERTABLE_H diff --git a/trunk/datainterpreterwidget.cpp b/trunk/datainterpreterwidget.cpp new file mode 100644 index 0000000..f71c7fa --- /dev/null +++ b/trunk/datainterpreterwidget.cpp @@ -0,0 +1,202 @@ +/******************************************************************************* +* 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 "datainterpreterwidget.h" +#include "registryhive.h" + +DataInterpreterWidget::DataInterpreterWidget(QWidget *p_parent) : + QWidget(p_parent) +{ + // Init private vars + this->data=QByteArray(); + this->endianness=DataInterpreterWidget::Endianness_LittleEndian; + + // Set widget layout. Setting it's parent to "this" will also call + // this->SetLayout. + this->p_widget_layout=new QVBoxLayout(this); + + // Create sub-widgets + this->p_data_interpreter_table=new DataInterpreterTable(); + this->p_endianness_selector_layout=new QHBoxLayout(); + this->p_endianness_selector_le=new QRadioButton(tr("Little endian")); + this->p_endianness_selector_be=new QRadioButton(tr("Big endian")); + + // Add endianness selector buttons to their layout + this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_le); + this->p_endianness_selector_layout->addWidget(this->p_endianness_selector_be); + + // Add sub-widgets to our layout + this->p_widget_layout->addWidget(this->p_data_interpreter_table); + this->p_widget_layout->addLayout(this->p_endianness_selector_layout); + + // Configure widget and sub-widgets + this->setContentsMargins(0,0,0,0); + this->p_widget_layout->setContentsMargins(0,0,0,0); + this->p_endianness_selector_layout->setContentsMargins(0,0,0,0); + this->p_endianness_selector_le->setContentsMargins(0,0,0,0); + this->p_endianness_selector_be->setContentsMargins(0,0,0,0); + this->setEnabled(false); + + // Set initial endianness selector state + this->p_endianness_selector_le->setChecked( + (this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + this->p_endianness_selector_be->setChecked( + (this->endianness==DataInterpreterWidget::Endianness_BigEndian)); + + // Connect signals + this->connect(this->p_endianness_selector_le, + SIGNAL(clicked(bool)), + this, + SLOT(SlotEndiannessSelectorLeClicked(bool))); + this->connect(this->p_endianness_selector_be, + SIGNAL(clicked(bool)), + this, + SLOT(SlotEndiannessSelectorBeClicked(bool))); +} + +DataInterpreterWidget::~DataInterpreterWidget() { + delete this->p_endianness_selector_le; + delete this->p_endianness_selector_be; + delete this->p_endianness_selector_layout; + delete this->p_data_interpreter_table; + delete this->p_widget_layout; +} + +void DataInterpreterWidget::SetData(QByteArray new_data) { + // Save new data and interpret it + this->data=new_data; + this->InterpretData(); +} + +void DataInterpreterWidget::InterpretData() { + // Get data length + int data_length=this->data.size(); + + // Remove old values from data interpreter table + this->p_data_interpreter_table->ClearValues(); + + if(data_length>=1) { + this->p_data_interpreter_table->AddValue("int8:", + RegistryHive::KeyValueToString( + this->data, + "int8")); + this->p_data_interpreter_table->AddValue("uint8:", + RegistryHive::KeyValueToString( + this->data, + "uint8")); + } + if(data_length>=2) { + this->p_data_interpreter_table->AddValue( + "int16:", + RegistryHive::KeyValueToString( + this->data, + "int16", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + this->p_data_interpreter_table->AddValue( + "uint16:", + RegistryHive::KeyValueToString( + this->data, + "uint16", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + } + if(data_length>=4) { + this->p_data_interpreter_table->AddValue( + "int32:", + RegistryHive::KeyValueToString( + this->data, + "int32", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + this->p_data_interpreter_table->AddValue( + "uint32:", + RegistryHive::KeyValueToString( + this->data, + "uint32", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + this->p_data_interpreter_table->AddValue( + "unixtime:", + RegistryHive::KeyValueToString( + this->data, + "unixtime", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + } + if(data_length>=8) { + this->p_data_interpreter_table->AddValue( + "int64:", + RegistryHive::KeyValueToString( + this->data, + "int64", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + this->p_data_interpreter_table->AddValue( + "uint64:", + RegistryHive::KeyValueToString( + this->data, + "uint64", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); +/* + TODO: Check how one could implement this + this->p_data_interpreter_table->AddValue( + "unixtime64:", + RegistryHive::KeyValueToString( + this->data, + "unixtime64", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); +*/ + this->p_data_interpreter_table->AddValue( + "filetime64:", + RegistryHive::KeyValueToString( + this->data, + "filetime", + 0, + 0, + this->endianness==DataInterpreterWidget::Endianness_LittleEndian)); + } +} + +void DataInterpreterWidget::SlotEndiannessSelectorLeClicked(bool checked) { + if(checked) { + // Save selected endianness and update interpreted values + this->endianness=DataInterpreterWidget::Endianness_LittleEndian; + this->InterpretData(); + } +} + +void DataInterpreterWidget::SlotEndiannessSelectorBeClicked(bool checked) { + if(checked) { + // Save selected endianness and update interpreted values + this->endianness=DataInterpreterWidget::Endianness_BigEndian; + this->InterpretData(); + } +} diff --git a/trunk/datainterpreter.h b/trunk/datainterpreterwidget.h similarity index 58% rename from trunk/datainterpreter.h rename to trunk/datainterpreterwidget.h index d1ee0a3..2eeace2 100644 --- a/trunk/datainterpreter.h +++ b/trunk/datainterpreterwidget.h @@ -1,68 +1,72 @@ /******************************************************************************* -* fred Copyright (c) 2011-2012 by Gillen Daniel * +* 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 DATAINTERPRETER_H -#define DATAINTERPRETER_H +#ifndef DATAINTERPRETERWIDGET_H +#define DATAINTERPRETERWIDGET_H #include -#include -#include -#include +#include +#include +#include +#include +#include -class DataInterpreter : public QTableWidget { +#include "datainterpretertable.h" + +class DataInterpreterWidget : public QWidget { Q_OBJECT public: - DataInterpreter(QWidget *p_parent=0); - ~DataInterpreter(); + enum Endianness { + Endianness_LittleEndian=0, + Endianness_BigEndian + }; - /* - * AddValue - * - * Add a value pair (name,value) to data interprter. - */ - void AddValue(QString name, QString value); - /* - * ClearValues - * - * Remove all value pairs from table - */ - void ClearValues(); + explicit DataInterpreterWidget(QWidget *p_parent=0); + ~DataInterpreterWidget(); - protected: /* - * sizeHintForColumn + * SetData * - * Needed reimplementation in order to allow resizeColumnsToContent - * to resize hidden columns too. + * Set data to be interpreted (will also interpret it). */ - int sizeHintForColumn(int column) const; - void contextMenuEvent(QContextMenuEvent *p_event); + void SetData(QByteArray new_data); private: - QAction *p_action_copy_value; + // Widget layout + QVBoxLayout *p_widget_layout; + // Sub-widgets + DataInterpreterTable *p_data_interpreter_table; + QHBoxLayout *p_endianness_selector_layout; + QRadioButton *p_endianness_selector_le; + QRadioButton *p_endianness_selector_be; + // Vars + QByteArray data; + int endianness; - private slots: - void SlotCopyValue(); + void InterpretData(); + private slots: + void SlotEndiannessSelectorLeClicked(bool checked); + void SlotEndiannessSelectorBeClicked(bool checked); }; -#endif // DATAINTERPRETER_H +#endif // DATAINTERPRETERWIDGET_H diff --git a/trunk/fred.pro b/trunk/fred.pro index d9791e7..d4db4c2 100644 --- a/trunk/fred.pro +++ b/trunk/fred.pro @@ -1,109 +1,111 @@ #******************************************************************************* # fred Copyright (c) 2011-2012 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 . * #******************************************************************************/ # Generate compileinfo.h system(bash compileinfo.sh > compileinfo.h) #compileinfo.target = compileinfo.h #compileinfo.commands = $$PWD/compileinfo.sh > compileinfo.h #QMAKE_EXTRA_TARGETS += compileinfo #PRE_TARGETDEPS += compileinfo.h # Build fred QMAKE_CXXFLAGS += -Wall QT += core \ gui \ script \ webkit CONFIG += console 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 \ searchresultwidget.cpp \ tabwidget.cpp \ - argparser.cpp + argparser.cpp \ + datainterpretertable.cpp \ + datainterpreterwidget.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 \ searchresultwidget.h \ tabwidget.h \ - argparser.h + argparser.h \ + datainterpretertable.h \ + datainterpreterwidget.h FORMS += mainwindow.ui \ dlgabout.ui \ dlgkeydetails.ui \ dlgreportviewer.ui \ dlgsearch.ui #LIBS += -lhivex LIBS += $$PWD/hivex/lib/.libs/libhivex.a \ #DEFINES += __STDC_FORMAT_MACROS RESOURCES += fred.qrc RC_FILE = fred.rc ICON = resources/fred.icns diff --git a/trunk/mainwindow.cpp b/trunk/mainwindow.cpp index f9db758..29faec1 100644 --- a/trunk/mainwindow.cpp +++ b/trunk/mainwindow.cpp @@ -1,745 +1,621 @@ /******************************************************************************* * fred Copyright (c) 2011-2012 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 #ifndef __MINGW32__ #define FRED_REPORT_TEMPLATE_DIR "/usr/share/fred/report_templates/" #else #define FRED_REPORT_TEMPLATE_DIR ".\\report_templates\\" #endif #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 "compileinfo.h" MainWindow::MainWindow(ArgParser *p_arg_parser) : QMainWindow(0), ui(new Ui::MainWindow) { ui->setupUi(this); // Initialize private vars this->p_args=p_arg_parser; 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; this->search_result_widgets.clear(); // 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 TabWidget(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_widget=new QWidget(this->p_horizontal_splitter2); - this->p_data_interpreter_layout= - new QVBoxLayout(this->p_data_interpreter_widget); - this->p_data_interpreter_layout->setContentsMargins(0,0,0,0); - this->p_data_interpreter=new DataInterpreter(); - - this->p_data_interpreter_endianes_widget=new QWidget(); - this->p_data_interpreter_endianes_layout= - new QHBoxLayout(this->p_data_interpreter_endianes_widget); - this->p_data_interpreter_endianes_layout->setContentsMargins(0,0,0,0); - this->p_data_interpreter_endianes_be=new QRadioButton(tr("Big endian")); - this->p_data_interpreter_endianes_le=new QRadioButton(tr("Little endian")); - - // Little endian is default - this->p_data_interpreter_endianes_le->setChecked(true); - - // Disable radio buttons until a hive is opened - this->p_data_interpreter_endianes_be->setEnabled(false); - this->p_data_interpreter_endianes_le->setEnabled(false); + this->p_data_interpreter_widget= + new DataInterpreterWidget(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->addTab(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_data_interpreter_endianes_layout-> - addWidget(this->p_data_interpreter_endianes_be); - this->p_data_interpreter_endianes_layout-> - addWidget(this->p_data_interpreter_endianes_le); - - this->p_data_interpreter_layout->addWidget(this->p_data_interpreter); - this->p_data_interpreter_layout-> - addWidget(this->p_data_interpreter_endianes_widget); - this->p_horizontal_splitter2->addWidget(this->p_hex_edit_widget); this->p_horizontal_splitter2->addWidget(this->p_data_interpreter_widget); 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_widget_policy= this->p_data_interpreter_widget->sizePolicy(); data_interpreter_widget_policy.setVerticalStretch(2); data_interpreter_widget_policy.setHorizontalStretch(0); this->p_data_interpreter_widget-> setSizePolicy(data_interpreter_widget_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_node_tree, SIGNAL(CurrentItemChanged(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_key_table, SIGNAL(CurrentItemChanged(QModelIndex)), this, SLOT(SlotKeyTableClicked(QModelIndex))); this->connect(this->p_hex_edit, SIGNAL(currentAddressChanged(int)), this, SLOT(SlotHexEditAddressChanged(int))); this->connect(this->p_tab_widget, SIGNAL(tabCloseRequested(int)), this, SLOT(SlotTabCloseButtonClicked(int))); // Add central widget this->setCentralWidget(this->p_horizontal_splitter); this->centralWidget()->setContentsMargins(4,4,4,0); // 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, react on some command line arguments if(this->p_args->IsSet("hive-file")) { this->OpenHive(this->p_args->GetArgVal("hive-file")); } } 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) { // Remove search results while(this->p_tab_widget->count()>1) { this->p_tab_widget->removeTab(this->p_tab_widget->count()-1); delete this->search_result_widgets.at(this->p_tab_widget->count()-1); this->search_result_widgets.removeLast(); } // 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(); - // Disable radio buttons - this->p_data_interpreter_endianes_be->setEnabled(false); - this->p_data_interpreter_endianes_le->setEnabled(false); + this->p_data_interpreter_widget->SetData(QByteArray()); + this->p_data_interpreter_widget->setEnabled(false); // 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 and to internal widget list SearchResultWidget *p_search_widget= new SearchResultWidget(this->p_tab_widget); p_search_widget->setEnabled(false); this->search_result_widgets.append(p_search_widget); this->connect(p_search_widget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(SlotSearchResultWidgetDoubleClicked(QModelIndex))); this->p_tab_widget->addTab(p_search_widget,tr("Search results"),true); 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 + // Built node path node_path=this->p_reg_node_tree_model->GetNodePath(index); // Create table model and attach it to the table view if(this->p_reg_key_table_model!=NULL) { + // If a previous model was set, delete it and clear hexedit etc... 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_data_interpreter_widget->SetData(QByteArray()); } this->p_reg_key_table_model=new RegistryKeyTableModel(this->p_hive,node_path); this->p_key_table->setModel(this->p_reg_key_table_model); // Set focus back to nodetree to be able to navigate with keyboard this->p_node_tree->setFocus(); } 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();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); // Set focus back to nodetree to be able to navigate with keyboard this->p_key_table->setFocus(); } 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("Byte offset: 0x%1 (%2)") .arg((uint16_t)hex_offset,4,16,QChar('0')) .arg(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::SlotSearchFinished() { delete this->p_search_thread; this->p_search_thread=NULL; this->ui->ActionSearch->setEnabled(true); // Enable result widget this->search_result_widgets.last()->setEnabled(true); } void MainWindow::SlotSearchResultWidgetDoubleClicked(QModelIndex index) { SearchResultWidget *p_sender; QString path; QString match_type; QString value; QString key=""; int i; if(!index.isValid()) return; // Get pointer to sender p_sender=(SearchResultWidget*)QObject::sender(); // Get path and matchtype path=p_sender->item(index.row(),0)->text(); match_type=p_sender->item(index.row(),1)->text(); value=p_sender->item(index.row(),2)->text(); if(match_type==tr("Node name")) { // Node name is not part of path. Add it if(path=="\\") path.append(value); else path.append("\\").append(value); } else if(match_type==tr("Key name")) { // Key name is stored in value key=value; } else if(match_type==tr("Key value")) { // Key name is part of path. Save and remove it QStringList nodes=path.split("\\",QString::SkipEmptyParts); key=nodes.at(nodes.count()-1); // Remove \ from path path.chop(key.length()+1); } // Expand treeview to correct node QList indexes= this->p_reg_node_tree_model->GetIndexListOf(path); for(i=0;ip_node_tree->expand(indexes.at(i)); } if(indexes.count()>0) { // Scroll to last expanded node, select it and update widgets this->p_node_tree->scrollTo(indexes.at(indexes.count()-1), QAbstractItemView::PositionAtCenter); this->p_node_tree->selectionModel()->clear(); this->p_node_tree->selectionModel()-> select(indexes.at(indexes.count()-1), QItemSelectionModel::Select); // TODO: This does not work!! this->SlotNodeTreeClicked(indexes.at(indexes.count()-1)); } // Select correct key if search matched on keay name / value if(key!="") { int row=this->p_reg_key_table_model->GetKeyRow(key); this->p_key_table->clearSelection(); this->p_key_table->scrollTo(this->p_reg_key_table_model->index(row,0), QAbstractItemView::PositionAtCenter); this->p_key_table->selectRow(row); this->SlotKeyTableClicked(this->p_reg_key_table_model->index(row,0)); } } void MainWindow::SlotTabCloseButtonClicked(int index) { // Delete tab widget and remove tab this->p_tab_widget->removeTab(index); delete this->search_result_widgets.at(index-1); this->search_result_widgets.removeAt(index-1); } 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("%1 v%2").arg(APP_TITLE,APP_VERSION)); } else { this->setWindowTitle(QString("%1 v%2 - %3").arg(APP_TITLE, APP_VERSION, filename.toLocal8Bit() .constData())); } } void MainWindow::UpdateDataInterpreter(int hex_offset) { - const char *p_data; - int remaining_data_len; - bool little_endian=this->p_data_interpreter_endianes_le->isChecked(); - - // 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; - - 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, - 0, - little_endian)); - this->p_data_interpreter->AddValue("uint16:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "uint16", - hex_offset, - 0, - little_endian)); - } - if(remaining_data_len>=4) { - this->p_data_interpreter->AddValue("int32:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "int32", - hex_offset, - 0, - little_endian)); - this->p_data_interpreter->AddValue("uint32:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "uint32", - hex_offset, - 0, - little_endian)); - this->p_data_interpreter->AddValue("unixtime:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "unixtime", - hex_offset, - 0, - little_endian)); - } - if(remaining_data_len>=8) { - this->p_data_interpreter->AddValue("int64:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "int64", - hex_offset, - 0, - little_endian)); - this->p_data_interpreter->AddValue("uint64:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "uint64", - hex_offset, - 0, - little_endian)); -/* - TODO: Check one could implement this - this->p_data_interpreter->AddValue("unixtime64:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "unixtime64", - hex_offset)); -*/ - this->p_data_interpreter->AddValue("filetime64:", - RegistryHive::KeyValueToString( - this->selected_key_value, - "filetime", - hex_offset, - 0, - little_endian)); - } + // Update data interpreter. There is currently no interpretition that uses + // more then 8 bytes, so only pass 8 bytes at max. + this->p_data_interpreter_widget->SetData( + this->selected_key_value.mid(hex_offset,8)); } 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); - // Enable radio buttons for endianes selection - this->p_data_interpreter_endianes_be->setEnabled(true); - this->p_data_interpreter_endianes_le->setEnabled(true); + // Enable data interpreter + this->p_data_interpreter_widget->setEnabled(true); this->UpdateWindowTitle(hive_file); } diff --git a/trunk/mainwindow.h b/trunk/mainwindow.h index 4eb288e..e1211a9 100644 --- a/trunk/mainwindow.h +++ b/trunk/mainwindow.h @@ -1,144 +1,151 @@ /******************************************************************************* * fred Copyright (c) 2011-2012 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 "argparser.h" #include "registryhive.h" #include "registrynodetree.h" #include "registrynodetreemodel.h" #include "registrykeytable.h" #include "registrykeytablemodel.h" #include "qhexedit/qhexedit.h" -#include "datainterpreter.h" +#include "datainterpreterwidget.h" #include "datareporter.h" #include "threadsearch.h" #include "searchresultwidget.h" #include "tabwidget.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(ArgParser *p_arg_parser); ~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 SlotSearchFinished(); void SlotSearchResultWidgetDoubleClicked(QModelIndex index); void SlotTabCloseButtonClicked(int index); +/* + void SlotDataInterpreterEndiannessBe(bool checked); + void SlotDataInterpreterEndiannessLe(bool checked); +*/ private: Ui::MainWindow *ui; ArgParser *p_args; 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; QList search_result_widgets; // Widgets etc... RegistryNodeTree *p_node_tree; RegistryKeyTable *p_key_table; TabWidget *p_tab_widget; QWidget *p_hex_edit_widget; QVBoxLayout *p_hex_edit_layout; QHexEdit *p_hex_edit; QLabel *p_hex_edit_status_bar; +/* QWidget *p_data_interpreter_widget; QVBoxLayout *p_data_interpreter_layout; DataInterpreter *p_data_interpreter; - QWidget *p_data_interpreter_endianes_widget; - QHBoxLayout *p_data_interpreter_endianes_layout; - QRadioButton *p_data_interpreter_endianes_be; - QRadioButton *p_data_interpreter_endianes_le; + QWidget *p_data_interpreter_endianness_widget; + QHBoxLayout *p_data_interpreter_endianness_layout; + QRadioButton *p_data_interpreter_endianness_be; + QRadioButton *p_data_interpreter_endianness_le; +*/ + DataInterpreterWidget *p_data_interpreter_widget; 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); }; #endif // MAINWINDOW_H diff --git a/trunk/registryhive.cpp b/trunk/registryhive.cpp index 7228815..7b2a64b 100644 --- a/trunk/registryhive.cpp +++ b/trunk/registryhive.cpp @@ -1,592 +1,592 @@ /******************************************************************************* * fred Copyright (c) 2011-2012 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 "registryhive.h" #include #include #include #include // TODO: __WORDSIZE is not defined under mingw and I currently have no idea how // to identify a 64bit windows #ifndef __WORDSIZE #define __WORDSIZE 32 #endif #if __WORDSIZE == 64 #define EPOCH_DIFF 0x19DB1DED53E8000 #else #define EPOCH_DIFF 0x19DB1DED53E8000LL #endif /* * RegistryHive */ RegistryHive::RegistryHive(QObject *p_parent) : QObject(p_parent) { this->erro_msg=""; this->is_error=false; this->hive_file=""; this->p_hive=NULL; this->is_hive_open=false; } /* * ~RegistryHive */ RegistryHive::~RegistryHive() { if(this->is_hive_open) this->Close(); } /* * Error */ bool RegistryHive::Error() { return this->is_error; } /* * GetErrorMsg */ QString RegistryHive::GetErrorMsg() { QString msg=this->erro_msg; this->erro_msg=""; this->is_error=false; return msg; } /* * Open */ bool RegistryHive::Open(QString file, bool read_only) { if(this->is_hive_open) return false; // Open hive file this->p_hive=hivex_open(file.toAscii().constData(), read_only ? 0 : HIVEX_OPEN_WRITE); if(this->p_hive==NULL) return false; // Set local vars this->hive_file=file; this->is_hive_open=true; return true; } /* * Close */ bool RegistryHive::Close(bool commit_changes) { if(this->is_hive_open) { if(commit_changes) { // Commit changes before closing hive. // TODO: Maybe it would be more secure to commit changes to a new file and // then move it over the original one. hivex_commit(this->p_hive,NULL,0); } // As hivex_close will _ALWAYS_ free the handle, we don't need the following // values anymore this->hive_file=""; this->is_hive_open=false; // Close hive if(hivex_close(this->p_hive)!=0) return false; } return true; } QString RegistryHive::Filename() { if(this->is_hive_open) return this->hive_file; return QString(); } /* * GetNodes */ QMap RegistryHive::GetNodes(QString path) { hive_node_h parent_node; // Get handle to last node in path if(!this->GetNodeHandle(path,&parent_node)) return QMap(); // Get and return nodes return this->GetNodesHelper(parent_node); } /* * GetNodes */ QMap RegistryHive::GetNodes(int parent_node) { if(parent_node==0) { this->SetError(tr("Invalid parent node handle specified!")); return QMap(); } // Get and return nodes return this->GetNodesHelper(parent_node); } /* * GetKeys */ QMap RegistryHive::GetKeys(QString path) { hive_node_h parent_node; // Get handle to last node in path if(!this->GetNodeHandle(path,&parent_node)) return QMap(); // Get and return keys return this->GetKeysHelper(parent_node); } /* * GetKeys */ QMap RegistryHive::GetKeys(int parent_node) { if(parent_node==0) { this->SetError(tr("Invalid parent node handle specified!")); return QMap(); } // Get and return keys return this->GetKeysHelper(parent_node); } /* * GetKeyValue */ QByteArray RegistryHive::GetKeyValue(QString path, QString key, int *p_value_type, size_t *p_value_len) { hive_node_h parent_node; hive_value_h hive_key; // Get handle to last node in path if(!this->GetNodeHandle(path,&parent_node)) return QByteArray(); // Get key handle hive_key=hivex_node_get_value(this->p_hive, parent_node,key.toAscii().constData()); if(hive_key==0) { this->SetError(tr("Unable to get key handle!")); *p_value_len=-1; return QByteArray(); } // Get and return key value return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len); } /* * GetKeyValue */ QByteArray RegistryHive::GetKeyValue(int hive_key, int *p_value_type, size_t *p_value_len) { if(hive_key==0) { this->SetError(tr("Invalid key handle specified!")); *p_value_type=-1; return QByteArray(); } // Get and return key value return this->GetKeyValueHelper(hive_key,p_value_type,p_value_len); } /* * KeyValueToString */ QString RegistryHive::KeyValueToString(QByteArray value, int value_type) { QString ret=""; int i=0; #define ToHexStr() { \ for(i=0;i0) { // Nothing to show return QString(); } // Get pointer to data at specified offset p_data=key_value.constData(); p_data+=offset; - // TODO: This will fail on platforms with different endianes! + // TODO: This will fail on platforms with different endianness! #define bswap_16(value) ((((value) & 0xff) << 8) | ((value) >> 8)) #define bswap_32(value) \ (((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \ (uint32_t)bswap_16((uint16_t)((value) >> 16))) #define bswap_64(value) \ (((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) << 32) | \ (uint64_t)bswap_32((uint32_t)((value) >> 32))) \ // ConvertFull name if(format=="int8" && remaining_data_len>=1) { ret=QString().sprintf("%d",*(int8_t*)p_data); } else if(format=="uint8" && remaining_data_len>=1) { ret=QString().sprintf("%u",*(uint8_t*)p_data); } else if(format=="int16" && remaining_data_len>=2) { int16_t val=*(int16_t*)p_data; if(little_endian) ret=QString().sprintf("%d",val); else ret=QString().sprintf("%d",bswap_16(val)); } else if(format=="uint16" && remaining_data_len>=2) { uint16_t val=*(uint16_t*)p_data; if(little_endian) ret=QString().sprintf("%u",val); else ret=QString().sprintf("%u",bswap_16(val)); } else if(format=="int32" && remaining_data_len>=4) { int32_t val=*(int32_t*)p_data; if(little_endian) ret=QString().sprintf("%d",val); else ret=QString().sprintf("%d",bswap_32(val)); } else if(format=="uint32" && remaining_data_len>=4) { uint32_t val=*(uint32_t*)p_data; if(little_endian) ret=QString().sprintf("%u",val); else ret=QString().sprintf("%u",bswap_32(val)); } else if(format=="unixtime" && remaining_data_len>=4) { uint32_t val=*(uint32_t*)p_data; if(!little_endian) val=bswap_32(val); if(val==0) { ret="n/a"; } else { QDateTime date_time; date_time.setTimeSpec(Qt::UTC); date_time.setTime_t(val); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(format=="int64" && remaining_data_len>=8) { int64_t val=*(int64_t*)p_data; if(little_endian) ret=QString("%1").arg(val); - else ret=QString("%1").arg(bswap_64(val)); + else ret=QString("%1").arg((int64_t)bswap_64(val)); } else if(format=="uint64" && remaining_data_len>=8) { uint64_t val=*(uint64_t*)p_data; if(little_endian) ret=QString("%1").arg(val); else ret=QString("%1").arg(bswap_64(val)); /* // TODO: Check how one could implement this } else if(format=="unixtime64" && remaining_data_len>=8) { if(*(uint64_t*)p_data==0) { ret="n/a"; } else { uint64_t secs=*(uint64_t*)p_data; QDateTime date_time; date_time.setTimeSpec(Qt::UTC); // Set 32bit part of date/time date_time.setTime_t(secs&0xFFFFFFFF); // Now add high 32bit part of date/time date_time.addSecs(secs>>32); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } */ } else if(format=="filetime" && remaining_data_len>=8) { uint64_t val=*(uint64_t*)p_data; if(!little_endian) val=bswap_64(val); if(val==0) { ret="n/a"; } else { // TODO: Warn if >32bit QDateTime date_time; date_time.setTimeSpec(Qt::UTC); date_time.setTime_t((val-EPOCH_DIFF)/10000000); ret=date_time.toString("yyyy/MM/dd hh:mm:ss"); } } else if(format=="ascii") { // TODO: This fails bad if the string is not null terminated!! It might be // wise checking for a null char here ret=QString().fromAscii((char*)p_data,length); } else if(format=="utf16" && remaining_data_len>=2) { ret=QString().fromUtf16((ushort*)p_data,length); } else { // Unknown variant type or another error return QString(); } return ret; } /* * KeyTypeToString */ QString RegistryHive::KeyTypeToString(int value_type) { QString ret=""; switch(value_type) { case hive_t_REG_NONE: ret="REG_NONE"; break; case hive_t_REG_SZ: ret="REG_SZ"; break; case hive_t_REG_EXPAND_SZ: ret="REG_EXPAND_SZ"; break; case hive_t_REG_BINARY: ret="REG_BINARY"; break; case hive_t_REG_DWORD: ret="REG_DWORD"; break; case hive_t_REG_DWORD_BIG_ENDIAN: ret="REG_DWORD_BIG_ENDIAN"; break; case hive_t_REG_LINK: ret="REG_LINK"; break; case hive_t_REG_MULTI_SZ: ret="REG_MULTI_SZ"; break; case hive_t_REG_RESOURCE_LIST: ret="REG_RESOURCE_LIST"; break; case hive_t_REG_FULL_RESOURCE_DESCRIPTOR: ret="REG_FULL_RESOURCE_DESC"; break; case hive_t_REG_RESOURCE_REQUIREMENTS_LIST: ret="REG_RESOURCE_REQ_LIST"; break; case hive_t_REG_QWORD: ret="REG_QWORD"; break; default: ret=QString().sprintf("0x%08X",(uint32_t)value_type); } return ret; } /* * SetError */ void RegistryHive::SetError(QString msg) { this->erro_msg=msg; this->is_error=true; } /* * GetNodeHandle */ bool RegistryHive::GetNodeHandle(QString &path, hive_node_h *p_node) { QStringList nodes; int i=0; // Get root node handle *p_node=hivex_root(this->p_hive); if(*p_node==0) { this->SetError(tr("Unable to get root node!")); return false; } if(path!="\\") { // If we aren't listing the root node, we have to get a handle to the // last node in the path. Split path into nodes nodes=path.split('\\',QString::SkipEmptyParts); // Iterate to the correct parent node for(i=0;ip_hive, *p_node, nodes.value(i).toAscii().constData()); if(*p_node==0) { this->SetError(tr("Unable to find node '%1'!").arg(nodes.value(i))); return false; } } } return true; } /* * GetNodesHelper */ QMap RegistryHive::GetNodesHelper(hive_node_h parent_node) { QMap keys; char *p_name; int i=0; // Get child nodes hive_node_h *child_nodes=hivex_node_children(this->p_hive,parent_node); if(child_nodes==NULL) { this->SetError( tr("Unable to enumerate child nodes!")); return QMap(); } // Build result keys.clear(); i=0; while(child_nodes[i]) { p_name=hivex_node_name(this->p_hive,child_nodes[i]); if(p_name==NULL) { this->SetError(tr("Unable to get node name!")); free(child_nodes); return QMap(); } keys.insert(QString(p_name),(int)child_nodes[i]); free(p_name); i++; } free(child_nodes); return keys; } /* * GetKeysHelper */ QMap RegistryHive::GetKeysHelper(hive_node_h parent_node) { QMap keys; char *p_name; int i=0; // Get child keys hive_value_h *p_keys=hivex_node_values(this->p_hive,parent_node); if(p_keys==NULL) { this->SetError( tr("Unable to enumerate child keys!")); return QMap(); } // Build result list keys.clear(); i=0; while(p_keys[i]) { p_name=hivex_value_key(this->p_hive,p_keys[i]); if(p_name==NULL) { this->SetError(tr("Unable to get key name!")); return QMap(); } keys.insert(QString(p_name),p_keys[i]); free(p_name); i++; } free(p_keys); return keys; } QByteArray RegistryHive::GetKeyValueHelper(hive_value_h hive_key, int *p_value_type, size_t *p_value_len) { QByteArray key_value; char *p_key_value; p_key_value=hivex_value_value(this->p_hive, hive_key, (hive_type*)p_value_type, p_value_len); if(p_key_value==NULL) { this->SetError(tr("Unable to get key value!")); *p_value_type=-1; return QByteArray(); } // Feed QByteArray and free p_key_value key_value=QByteArray(p_key_value,*p_value_len); free(p_key_value); return key_value; }