Page MenuHomePhabricator

No OneTemporary

Size
75 KB
Referenced Files
None
Subscribers
None
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 <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
-#include "datainterpreter.h"
+#include "datainterpretertable.h"
#include <QHeaderView>
#include <QFontMetrics>
#include <QMenu>
#include <QApplication>
#include <QClipboard>
-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;i<this->rowCount();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 <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
-#ifndef DATAINTERPRETER_H
-#define DATAINTERPRETER_H
+#ifndef DATAINTERPRETERTABLE_H
+#define DATAINTERPRETERTABLE_H
#include <QWidget>
#include <QTableWidget>
#include <QContextMenuEvent>
#include <QAction>
-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 <gillen.dan@pinguin.lu> *
+* *
+* 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 <http://www.gnu.org/licenses/>. *
+*******************************************************************************/
+
+#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 <gillen.dan@pinguin.lu> *
+* fred Copyright (c) 2011 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
-#ifndef DATAINTERPRETER_H
-#define DATAINTERPRETER_H
+#ifndef DATAINTERPRETERWIDGET_H
+#define DATAINTERPRETERWIDGET_H
#include <QWidget>
-#include <QTableWidget>
-#include <QContextMenuEvent>
-#include <QAction>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QRadioButton>
+#include <QString>
+#include <QByteArray>
-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 <gillen.dan@pinguin.lu> *
# *
# 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 <http://www.gnu.org/licenses/>. *
#******************************************************************************/
# 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 <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#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 <QFileDialog>
#include <QMessageBox>
#include <QStringList>
#include <QDesktopWidget>
#include <QDir>
#include <QSplitter>
#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<QByteArray> 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 \<key name> from path
path.chop(key.length()+1);
}
// Expand treeview to correct node
QList<QModelIndex> indexes=
this->p_reg_node_tree_model->GetIndexListOf(path);
for(i=0;i<indexes.count();i++) {
this->p_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;i<categories.count();i++) {
// First create category submenu
p_category_entry=this->ui->MenuReports->addMenu(categories.value(i));
// Now add category reports
reports=this->p_data_reporter->GetAvailableReports(categories.value(i));
for(ii=0;ii<reports.count();ii++) {
p_report_entry=new QAction(reports.value(ii),p_category_entry);
p_category_entry->addAction(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 <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QLabel>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QSplitter>
#include <QString>
#include <QByteArray>
#include <hivex.h>
#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<SearchResultWidget*> 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 <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include "registryhive.h"
#include <QStringList>
#include <QDateTime>
#include <stdlib.h>
#include <stdio.h>
// 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<QString,int> RegistryHive::GetNodes(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetNodes
*/
QMap<QString,int> RegistryHive::GetNodes(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// Get and return nodes
return this->GetNodesHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(QString path) {
hive_node_h parent_node;
// Get handle to last node in path
if(!this->GetNodeHandle(path,&parent_node)) return QMap<QString,int>();
// Get and return keys
return this->GetKeysHelper(parent_node);
}
/*
* GetKeys
*/
QMap<QString,int> RegistryHive::GetKeys(int parent_node) {
if(parent_node==0) {
this->SetError(tr("Invalid parent node handle specified!"));
return QMap<QString,int>();
}
// 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;i<value.size();i++) { \
ret.append(QString().sprintf("%02X ",(uint8_t)(value.constData()[i]))); \
} \
ret.chop(1); \
}
switch(value_type) {
case hive_t_REG_NONE:
// Just a key without a value, but to be certain...
ToHexStr();
break;
case hive_t_REG_SZ:
// A Windows string (encoding is unknown, but often UTF16-LE)
// TODO: What happens if encoding is not UTF16-LE ??? Thx Billy!!!
ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
break;
case hive_t_REG_EXPAND_SZ:
// A Windows string that contains %env% (environment variable expansion)
ret=value.size() ? QString().fromUtf16((ushort*)(value.constData())) : "";
break;
case hive_t_REG_BINARY:
// A blob of binary
ToHexStr();
break;
case hive_t_REG_DWORD:
// DWORD (32 bit integer), little endian
ret=QString().sprintf("0x%08X",*(uint32_t*)value.constData());
break;
case hive_t_REG_DWORD_BIG_ENDIAN:
// DWORD (32 bit integer), big endian
ret=QString().sprintf("0x%08X",*(uint32_t*)value.constData());
break;
case hive_t_REG_LINK:
// Symbolic link to another part of the registry tree
ToHexStr();
break;
case hive_t_REG_MULTI_SZ:
// Multiple Windows strings.
// See http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx
ToHexStr();
break;
case hive_t_REG_RESOURCE_LIST:
// Resource list
ToHexStr();
break;
case hive_t_REG_FULL_RESOURCE_DESCRIPTOR:
// Resource descriptor
ToHexStr();
break;
case hive_t_REG_RESOURCE_REQUIREMENTS_LIST:
// Resouce requirements list
ToHexStr();
break;
case hive_t_REG_QWORD:
// QWORD (64 bit integer). Usually little endian.
ret=
QString("0x%1").arg((quint64)(*(uint64_t*)value.constData()),16,16,QChar('0'));
break;
default:
ToHexStr();
}
#undef ToHexStr
return ret;
}
/*
* KeyValueToString
*/
QString RegistryHive::KeyValueToString(QByteArray key_value,
QString format,
int offset,
int length,
bool little_endian)
{
int remaining_data_len;
const char *p_data;
QString ret="";
// Calculate how many bytes are remainig after specified offset
remaining_data_len=key_value.size()-offset;
if(!remaining_data_len>0) {
// 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;i<nodes.count();i++) {
// printf("Spotting node '%s'\n",nodes.value(i).toAscii().constData());
*p_node=hivex_node_get_child(this->p_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<QString,int> RegistryHive::GetNodesHelper(hive_node_h parent_node) {
QMap<QString,int> 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<QString,int>();
}
// 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<QString,int>();
}
keys.insert(QString(p_name),(int)child_nodes[i]);
free(p_name);
i++;
}
free(child_nodes);
return keys;
}
/*
* GetKeysHelper
*/
QMap<QString,int> RegistryHive::GetKeysHelper(hive_node_h parent_node) {
QMap<QString,int> 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<QString,int>();
}
// 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<QString,int>();
}
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;
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, May 11, 6:33 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1247631
Default Alt Text
(75 KB)

Event Timeline